为什么我不能在打开的文件上两次调用read()?


98

对于我正在做的练习,我试图使用read()方法两次读取给定文件的内容。奇怪的是,当我第二次调用它时,似乎没有将文件内容返回为字符串?

这是代码

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

我当然知道这不是最有效或最好的方法,这不是重点。问题是,为什么我不能打read()两次电话?我是否需要重置文件句柄?还是关闭/重新打开文件以执行此操作?


2
您从何处得知读取不会更改文件状态?您正在使用什么参考书或教程?
S.Lott

我相信关闭和重新打开文件应该基于下面的答案。
安东尼2010年

@Shynthriir:关闭并重新打开文件并不总是一个好主意,因为它可能会对系统产生其他影响(临时文件,incron等)。
伊格纳西奥·巴斯克斯

3
我只想指出一个明显的事实:您DID两次调用read()!

4
W / R / T / S.Lott,从5年开始:确实需要在python文档中。显然不应以为读取文件对象会改变任何状态,特别是如果习惯于使用不可变数据/函数式编程的话……
Paul Gowder

Answers:


156

调用read()将读取整个文件,并将读取的游标留在文件的末尾(仅读取其他内容)。如果您希望一次阅读一定数量的行,则可以使用readline()readlines()或使用 遍历行for line in handle:

要直接回答您的问题,请在读取文件后read()使用seek(0),将读取的光标返回到文件的开头(文档在此处)。如果您知道文件不会太大,也可以将read()输出保存到变量中,并在findall表达式中使用它。

附言 完成操作后,不要忘记关闭文件;)


4
+1,是的,请阅读临时变量以避免不必要的文件I / O。浪费任何内存是错误的做法,因为变量(显式)变少了。
尼克T 2010年

2
@NickT:我希望OS会缓存多次读取的小文件(至少在Linux / OSX上),因此不会有多余的文件I / O可供读取两次。不能容纳在内存中的大文件不会被缓存,但是您不想将它们读入变量,因为您将开始交换。因此,如有疑问,请务必多次阅读。如果您确定文件很小,请执行提供最佳程序的任何操作。
克劳德(Claude)

3
可以使用进行自动拆卸with
Cees Timmerman

30

是的,如上所述

我只写一个例子:

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

17

到目前为止,回答此问题的每个人都是绝对正确的- read()遍历文件,因此在调用该文件后,就无法再次调用它。

我要补充的是,在您的特定情况下,您无需重新查找文件或重新打开文件,您只需将已阅读的文本存储在局部变量中,然后使用两次,或者在您的程序中进行任意多次:

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实际上,这是此练习的建议解决方案(code.google.com/intl/de-DE/edu/languages/google-python-class/…)。但是不知何故我没有想到将字符串存储在变量中。天哪!
helpermethod 2010年

1
对于Python3,请使用pathlib。from pathlib import Path; text = Path(filename).read_text()负责打开,关闭等操作
PaulMcG


2

每个打开的文件都有一个关联的位置。
当您读取()时,您将从该位置读取。例如read(10),从一个新打开的文件中读取前10个字节,然后另一个read(10)读取后10个字节。 read()不带参数的文件将读取文件的所有内容,而将文件位置保留在文件末尾。下次致电时read(),没有任何内容可供阅读。

您可以seek用来移动文件位置。或者在您的情况下更好的方法是做一个read()并保留两个搜索的结果。


1

read() 消耗。因此,您可以重设文件,或在重新读取之前寻求开始。或者,如果它read(n)适合您的任务,则可以用来仅消耗n字节。


1

我总是发现读取方法有点像在黑暗的小巷中漫步。您会停下来停下来,但是如果您不计算步数,则不确定您走了多远。Seek通过重新定位来提供解决方案,另一个选项是Tell,它返回沿文件的位置。可能是Python文件api可以将读取和查找合并为一个read_from(position,bytes)以使其更简单-直到发生这种情况,您应该阅读此页面

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.