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

Posted

技术标签:

【中文标题】为啥我不能在打开的文件上调用 read() 两次?【英文标题】:Why can't I call read() twice on an open file?为什么我不能在打开的文件上调用 read() 两次? 【发布时间】:2011-04-23 19:08:27 【问题描述】:

对于我正在进行的练习,我尝试使用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() 打两次电话?我必须重置文件句柄吗?或者关闭/重新打开文件以执行此操作?

【问题讨论】:

您从哪里得到 read 不会改变文件状态的想法?您使用的是什么参考资料或教程? 我相信关闭和重新打开文件应该可以根据以下答案进行。 @Shynthriir:关闭并重新打开文件并不总是一个好主意,因为它可能会对系统产生其他影响(临时文件、incron 等)。 我只想声明一个显而易见的事实:您DID 调用了两次 read()! W/R/T/S.Lott,从 5 年开始:这确实需要在 python 文档中。显然,人们应该假设读取文件对象会改变任何东西的状态,特别是如果一个人习惯于使用不可变数据/函数式编程...... 【参考方案1】:

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

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

附言。完成后不要忘记关闭文件。

【讨论】:

+1,是的,请阅读临时变量以避免不必要的文件 I/O。这是一种虚假的经济,因为您的(显式)变量较少,所以您正在节省任何内存。 @NickT:我希望一个被多次读取的小文件会被操作系统缓存(至少在 Linux/OSX 上),所以不需要额外的文件 I/O 来读取两次。不适合内存的大文件不会被缓存,但您不想将它们读入变量,因为您将开始交换。因此,如有疑问,请务必多次阅读。如果您确定文件很小,请尽一切可能提供最好的程序。 可以使用with自动拆除。【参考方案2】:

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

我只写一个例子:

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

【讨论】:

【参考方案3】:

到目前为止,回答这个问题的每个人都绝对正确 - 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 实际上,这是本练习的建议解决方案 (code.google.com/intl/de-DE/edu/languages/google-python-class/…)。但不知何故,我没想过将字符串存储在变量中。哦! 对于 Python3,使用 pathlib。 from pathlib import Path; text = Path(filename).read_text() 负责打开、关闭等操作。【参考方案4】:

我总是觉得阅读方法有点像在黑暗的小巷里散步。你往下走一点停下来,但如果你不计算你的步数,你就不确定你走了多远。 Seek 通过重新定位给出解决方案,另一个选项是 Tell,它返回文件中的位置。可能是 Python 文件 api 可以将 read 和 seek 结合到 read_from(position,bytes) 中以使其更简单——在这种情况发生之前,您应该阅读this page。

【讨论】:

【参考方案5】:

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

【讨论】:

【参考方案6】:

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

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

【讨论】:

【参考方案7】:

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

【讨论】:

以上是关于为啥我不能在打开的文件上调用 read() 两次?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的word excel 一次打不开,必须两次才能打开,在“打开”中选择文件可以打开。

为啥我不能对相同的数据进行两次迭代?

为啥 sys.stdout.write 被调用两次?

汇编 调用C语言Scanf为啥会要求输两次

为啥文件打开对话框在单击 FireFox 中的按钮时打开两次

为啥我的方法在 iPhone/iPod 上被调用了两次,但在 iPad 上却没有?