Tại sao tôi không thể gọi read () hai lần trên một tệp đang mở?


98

Đối với một bài tập tôi đang làm, tôi đang cố đọc nội dung của một tệp đã cho hai lần bằng read()phương pháp này. Thật kỳ lạ, khi tôi gọi nó lần thứ hai, nó dường như không trả về nội dung tệp dưới dạng chuỗi?

Đây là mã

f = f.open()

# get the year
match = re.search(r'Popularity in (\d+)', f.read())

if match:
  print match.group(1)

# get all the names
matches = re.findall(r'<td>(\d+)</td><td>(\w+)</td><td>(\w+)</td>', f.read())

if matches:
  # matches is always None

Tất nhiên tôi biết rằng đây không phải là cách hiệu quả nhất hoặc tốt nhất, đây không phải là vấn đề ở đây. Vấn đề là, tại sao tôi không thể gọi read()hai lần? Tôi có phải đặt lại xử lý tệp không? Hay đóng / mở lại tệp để làm điều đó?


2
Bạn lấy ý tưởng từ đâu mà đọc sẽ không thay đổi trạng thái của tệp? Bạn đang sử dụng tài liệu tham khảo hoặc hướng dẫn nào?
S.Lott

Tôi tin rằng việc đóng và mở lại tệp sẽ hoạt động dựa trên các anwers bên dưới.
Anthony

@Shynthriir: Đóng và mở lại tệp không phải lúc nào cũng là một ý kiến ​​hay vì nó có thể gây ra các tác động khác trong hệ thống (tệp tạm thời, tệp incron, v.v.).
Ignacio Vazquez-Abrams,

3
Tôi chỉ muốn nói rõ ràng rằng: Bạn DID gọi read () hai lần!

4
W / R / T / S.Lott và từ 5 năm trở đi: điều này thực sự cần phải có trong tài liệu python. Nó không phải là rõ ràng rằng người ta nên cho rằng đọc một đối tượng tập tin sẽ thay đổi trạng thái của bất cứ điều gì, đặc biệt là nếu một được sử dụng để làm việc với các lập trình dữ liệu bất biến / chức năng kiểu ...
Paul Gowder

Câu trả lời:


156

Việc gọi read()đọc toàn bộ tệp và để con trỏ đọc ở cuối tệp (không còn gì để đọc). Nếu bạn đang tìm kiếm để đọc một số lượng nhất định của dòng tại một thời điểm bạn có thể sử dụng readline(), readlines()hoặc lặp qua đường dây với for line in handle:.

Để trả lời trực tiếp câu hỏi của bạn, sau khi một tệp đã được đọc, read()bạn có thể sử dụng seek(0)để trả con trỏ đã đọc về đầu tệp (tài liệu có ở đây ). Nếu bạn biết tệp sẽ không quá lớn, bạn cũng có thể lưu kết read()quả đầu ra vào một biến, sử dụng nó trong biểu thức tìm kiếm của bạn.

Ps. Đừng quên đóng tệp sau khi bạn hoàn tất;)


4
+1, Có, vui lòng đọc biến tạm thời để tránh I / O tệp không cần thiết. Đó là một nền kinh tế sai lầm khi bạn đang tiết kiệm bất kỳ bộ nhớ nào bởi vì bạn có ít biến (rõ ràng) hơn.
Nick T

2
@NickT: Tôi hy vọng rằng một tệp nhỏ được đọc nhiều lần sẽ được hệ điều hành lưu vào bộ nhớ đệm (ít nhất là trên Linux / OSX), vì vậy không có tệp I / O bổ sung nào để đọc hai lần. Các tệp lớn không vừa với bộ nhớ sẽ không được lưu vào bộ nhớ đệm, nhưng bạn không muốn đọc chúng thành một biến vì bạn sẽ bắt đầu hoán đổi. Vì vậy, trong trường hợp nghi ngờ, hãy luôn đọc nhiều lần. Nếu bạn biết chắc các tệp nhỏ, hãy làm bất cứ điều gì mang lại chương trình đẹp nhất.
Claude

3
Xé xuống có thể được tự động hóa với with.
Cees Timmerman

30

vâng, như trên ...

tôi sẽ chỉ viết một ví dụ:

>>> a = open('file.txt')
>>> a.read()
#output
>>> a.seek(0)
>>> a.read()
#same output

17

Tất cả những người đã trả lời câu hỏi này cho đến nay đều hoàn toàn đúng - read()chuyển qua tệp, vì vậy sau khi bạn đã gọi nó, bạn không thể gọi lại.

Điều tôi sẽ nói thêm là trong trường hợp cụ thể của bạn, bạn không cần phải quay lại bắt đầu hoặc mở lại tệp, bạn chỉ có thể lưu trữ văn bản bạn đã đọc trong một biến cục bộ và sử dụng nó hai lần, hoặc bao nhiêu lần tùy thích, trong chương trình của bạn:

f = f.open()
text = f.read() # read the file into a local variable
# get the year
match = re.search(r'Popularity in (\d+)', text)
if match:
  print match.group(1)
# get all the names
matches = re.findall(r'<td>(\d+)</td><td>(\w+)</td><td>(\w+)</td>', text)
if matches:
  # matches will now not always be None

1
+1 Thực ra đây là giải pháp được đề xuất cho bài tập này ( code.google.com/intl/de-DE/edu/languages/google-python-class/… ). Nhưng bằng cách nào đó, tôi đã không nghĩ đến việc lưu trữ chuỗi trong một biến. Ôi!
helpermethod

1
Với Python3, hãy sử dụng pathlib. from pathlib import Path; text = Path(filename).read_text()
Đảm nhận

14

Con trỏ đọc di chuyển đến sau byte / ký tự được đọc cuối cùng. Sử dụng seek()phương pháp để tua lại con trỏ đã đọc về đầu.


2

Mỗi tệp đang mở đều có một vị trí liên quan.
Khi bạn đọc () bạn đọc từ vị trí đó. Ví dụ: read(10)đọc 10 byte đầu tiên từ một tệp mới mở, sau đó một tệp khác read(10)đọc 10 byte tiếp theo. read()không có đối số đọc tất cả nội dung của tệp, để lại vị trí tệp ở cuối tệp. Lần sau bạn gọi read()sẽ không có gì để đọc.

Bạn có thể sử dụng seekđể di chuyển vị trí tệp. Hoặc có lẽ tốt hơn trong trường hợp của bạn là thực hiện một read()và giữ nguyên kết quả cho cả hai lần tìm kiếm.


1

read() tiêu thụ . Vì vậy, bạn có thể đặt lại tệp hoặc tìm cách bắt đầu trước khi đọc lại. Hoặc, nếu nó phù hợp với nhiệm vụ của bạn, bạn có thể sử dụng read(n)để chỉ sử dụng nbyte.


1

Tôi luôn thấy phương pháp đọc này giống như một chuyến đi bộ xuống một con hẻm tối. Bạn đi xuống một chút và dừng lại nhưng nếu bạn không đếm số bước của mình, bạn không chắc mình đã đi được bao xa. Seek đưa ra giải pháp bằng cách định vị lại vị trí, tùy chọn còn lại là Tell sẽ trả về vị trí dọc theo tệp. Có thể api tệp Python có thể kết hợp read và seek thành read_from (vị trí, byte) để làm cho nó đơn giản hơn - cho đến khi điều đó xảy ra, bạn nên đọc trang này .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.