我正在使用python3.2解析大小为1到10GB的日志文件,需要搜索具有特定正则表达式(某种时间戳)的行,并且我想找到最后一次出现。
我已经尝试使用:
for line in reversed(list(open("filename")))
导致非常糟糕的性能(在好的情况下)和MemoryError在坏的情况下。
在线程:用python倒序读取文件,我没有找到任何好的答案。
我找到了以下解决方案:Python的头,尾和反向读取文本文件的行非常有希望,但是它不能在python3.2中用于error:
NameError: name 'file' is not defined
我后来试图用File(TextIOWrapper)
代替File(file)
,因为这是对象内置函数open()
返回,但是这导致了更多的错误(我可以详细说明,如果有人建议这是正确的方式:))
这是一个你想要的函数
def reverse_lines(filename, BUFSIZE=4096):
f = open(filename, "rb")
f.seek(0, 2)
p = f.tell()
remainder = ""
while True:
sz = min(BUFSIZE, p)
p -= sz
f.seek(p)
buf = f.read(sz) + remainder
if 'n' not in buf:
remainder = buf
else:
i = buf.index('n')
for L in buf[i+1:].split("n")[::-1]:
yield L
remainder = buf[:i]
if p == 0:
break
yield remainder
的工作原理是从文件的末尾读取一个缓冲区(默认为4kb),并反向生成其中的所有行。然后它向后移动4k,直到文件的开始。代码可能需要保持超过4k的内存,以防在正在处理的部分中没有换行(非常长的行)。
您可以使用代码
for L in reverse_lines("my_big_file"):
... process L ...
如果您不想读取整个文件,您可以始终使用seek
。下面是一个示例:
$ cat words.txt
foo
bar
baz
[6] oz123b@debian:~ $ ls -l words.txt
-rw-r--r-- 1 oz123 oz123 12 Mar 9 19:38 words.txt
文件大小为12字节。您可以通过将光标向前移动8位来跳转到最后一项:
In [3]: w=open("words.txt")
In [4]: w.seek(8)
In [5]: w.readline()
Out[5]: 'bazn'
为了完成我的答案,下面是如何反向打印这些行:
w=open('words.txt')
In [6]: for s in [8, 4, 0]:
...: _= w.seek(s)
...: print(w.readline().strip())
...:
baz
bar
foo
您必须探索文件的数据结构和每行的大小。我的很简单,因为它是用来演示原理的。