17

我正在尝试在文本文件末尾附近找到一个字符串。问题是文本文件的大小可能会有很大差异。从 3MB 到 4GB。但是每次我尝试运行脚本在大约 3GB 的文本文件中查找此字符串时,我的计算机都会出现内存不足的情况。所以我想知道python是否有办法找到文件的大小,然后读取它的最后一个兆字节。

我目前使用的代码如下,但是就像我之前说的,我似乎没有足够大的内存来读取这么大的文件。

find_str = "ERROR"
file = open(file_directory)                           
last_few_lines​ = file.readlines()[-20:]   

error​ = False  

for line in ​last_few_lines​:
    if find_str in line:
    ​    error​ = True
4

3 回答 3

35

使用file.seek()

import os
find_str = "ERROR"
error = False
# Open file with 'b' to specify binary mode
with open(file_directory, 'rb') as file:
    file.seek(-1024 * 1024, os.SEEK_END)  # Note minus sign
    if find_str in file.read():
        error = True

打开文件时必须指定二进制模式,否则会出现“未定义的行为”。在 python2 下,它可能仍然有效(它对我有用),但在 python3 下,如果文件以默认文本模式打开,seek()则会引发异常。io.UnsupportedOperationpython 3 文档在这里。尽管从这些文档中并不清楚,但SEEK_*常量仍在os模块中。

更新:正如 Chris Betti 所建议的,使用with声明来进行更安全的资源管理。

于 2013-09-27T08:43:31.333 回答
2

您可以使用带有双端队列的尾部配方来获取大文件的最后几行:n

from collections import deque

def tail(fn, n):
    with open(fn) as fin:
        return list(deque(fin, n))

现在测试一下。

首先创建一个大文件:

>>> with open('/tmp/lines.txt', 'w') as f:
...    for i in range(1,10000000+1):
...       print >> f, 'Line {}'.format(i)  # Python 3: print('Line {}'.format(i), file=f)

# about 128 MB on my machine

然后测试:

print tail('/tmp/lines.txt', 20) 
# ['Line 9999981\n', 'Line 9999982\n', 'Line 9999983\n', 'Line 9999984\n', 'Line 9999985\n', 'Line 9999986\n', 'Line 9999987\n', 'Line 9999988\n', 'Line 9999989\n', 'Line 9999990\n', 'Line 9999991\n', 'Line 9999992\n', 'Line 9999993\n', 'Line 9999994\n', 'Line 9999995\n', 'Line 9999996\n', 'Line 9999997\n', 'Line 9999998\n', 'Line 9999999\n', 'Line 10000000\n']

这将返回文件的最后 n 行而不是文件的最后 X 个字节。数据的大小与行的大小相同——而不是文件的大小。文件对象 fin用作文件行的迭代器,因此整个文件不会一次全部驻留在内存中。

于 2013-09-27T10:05:42.427 回答
1

建议的答案 usingseek是您问题的正确答案,但我认为这不是您真正想要做的。您的解决方案将整个文件加载到内存中,只是为了获取最后 20 行。这是你的问题的主要原因。以下将解决您的内存问题:

for line in file(file_directory):
    if find_str in line:
        error = True

这将遍历文件中的所有行,但在处理完这些行后释放它们。我猜,这个解决方案已经比你的快得多,所以不需要进一步优化。但是如果你真的想只有最后 20 行,但是双端队列中的行最大长度为 20。

于 2013-09-27T10:03:38.103 回答