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

Why can't I call read() twice on an open file?

提问人:helpermethod 提问时间:10/11/2010 最后编辑:Glen Sellehelpermethod 更新时间:1/15/2022 访问量:93746

问:

对于我正在做的练习,我正在尝试使用该方法两次读取给定文件的内容。奇怪的是,当我第二次调用它时,它似乎没有将文件内容作为字符串返回?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()

Python IO

评论

2赞 S.Lott 10/11/2010
您从哪里得到读取不会更改文件状态的想法?您使用的是什么参考资料或教程?
1赞 Ignacio Vazquez-Abrams 10/11/2010
@Shynthriir:关闭并重新打开文件并不总是一个好主意,因为它可能会在系统中产生其他影响(临时文件、incron 等)。
4赞 10/11/2010
我只想说明一个显而易见的事实:你确实调用了read()两次!
6赞 Paul Gowder 10/2/2015
W/R/T/ S.Lott,从 5 年开始:这确实需要在 python 文档中。很明显,人们应该假设读取文件对象会改变任何事物的状态,特别是如果一个人习惯于使用不可变的数据/函数式编程......
1赞 Karl Knechtel 11/25/2022
@PaulGowder不同意 - 因为这是由文件的基本性质引起的,并且在每种编程语言中都以相同的方式工作。当然,从文件中读取会更改文件对象的状态 - 因为否则它怎么知道读取了什么,以及从哪里开始下一次读取? 答案是肯定的“阅读文件的其余部分;然后读取文件的其余部分“第二次得到一个空结果,原因与”从文件中读取一行;然后从文件中读取一个 ilne“每次都会得到不同的行。没有它,你怎么能遍历文件?

答:

197赞 Tim 10/11/2010 #1

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

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

Ps.不要忘记在完成后关闭文件。

评论

4赞 Nick T 10/11/2010
+1,是的,请读取临时变量以避免不必要的文件 I/O。你正在节省任何内存,因为你有更少的(显式)变量,这是一种错误的经济。
3赞 Claude 6/4/2014
@NickT:我希望操作系统会缓存多次读取的小文件(至少在 Linux/OSX 上),因此没有额外的文件 I/O 来读取两次。不适合内存的大文件不会被缓存,但你不想将它们读入变量中,因为你会开始交换。因此,如有疑问,请务必多读几遍。如果您确定文件很小,请执行任何提供最佳程序的操作。
5赞 Cees Timmerman 1/20/2016
拆卸可以自动使用。
15赞 Ignacio Vazquez-Abrams 10/11/2010 #2

读取指针移动到最后一个读取字节/字符之后。使用该方法将读取指针倒回开头。seek()

3赞 Douglas Leeder 10/11/2010 #3

每个打开的文件都有一个关联的位置。
当你读()时,你从那个位置读。 例如,从新打开的文件中读取前 10 个字节,然后另一个读取接下来的 10 个字节。 Without Arguments 读取文件的所有内容,将文件位置保留在文件末尾。下次你打电话时,没有什么可读的。
read(10)read(10)read()read()

可用于移动文件位置。或者,在您的情况下,更好的做法是执行一个并保留两个搜索的结果。seekread()

22赞 Tom Anderson 10/11/2010 #4

到目前为止,回答这个问题的每个人都是绝对正确的 - 在文件中移动,所以在你调用它之后,你不能再次调用它。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赞 helpermethod 10/12/2010
+1 实际上,这是本练习的建议解决方案(code.google.com/intl/de-DE/edu/languages/google-python-class/...)。但不知何故,我没有想到将字符串存储在变量中。哎呀!
1赞 PaulMcG 6/19/2017
在 Python3 中,使用 pathlib。 负责打开、关闭等。from pathlib import Path; text = Path(filename).read_text()
1赞 towi 10/11/2010 #5

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

50赞 Ant 10/11/2010 #6

正如其他答案所建议的那样,您应该使用 .seek()

我只写一个例子:

>>> a = open('file.txt')
>>> a.read()
#output
>>> a.seek(0)
>>> a.read()
#same output
-1赞 whatnick 10/11/2010 #7

我总是觉得阅读方法有点像走在一条黑暗的小巷里。你往下走一点,然后停下来,但如果你不计算你的步数,你就不确定你走了多远。Seek 通过重新定位来提供解决方案,另一个选项是 Tell,它返回沿文件的位置。可能是 Python 文件 api 可以将 read 和 seek 组合成一个read_from(position,bytes) 以使其更简单 - 在此之前,您应该阅读此页面