如何在python3.2中以反向顺序读取文件而不将整个文件读取到内存中



我正在使用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

您必须探索文件的数据结构和每行的大小。我的很简单,因为它是用来演示原理的。

相关内容

  • 没有找到相关文章

最新更新