如何有效地读取非常大的 gzip 日志文件的最后一行?

How to efficiently read the last line of very big gzipped log file?

我想从一个大的 gzip 日志文件中获取最后一行,而不必迭代所有其他行,因为它是一个大文件。

我已阅读 and in particular 大文件,但它不适用于 gzip 文件。确实,我试过了:

import gzip

with gzip.open(f, 'rb') as g:
    g.seek(-2, os.SEEK_END) 
    while g.read(1) != b'\n':  # Keep reading backward until you find the next break-line
        g.seek(-2, os.SEEK_CUR) 
    print(g.readline().decode())

但在我非常标准的笔记本电脑上,压缩 10 MB / 解压缩 130 MB 的文件已经花费了 80 多秒!

问题:如何使用 Python?

有效地查找到压缩文件的最后一行

旁注:如果未压缩,此方法非常快:130 MB 文件只需 1 毫秒:

import os, time
t0 = time.time()
with open('test', 'rb') as g:
    g.seek(-2, os.SEEK_END) 
    while g.read(1) != b'\n': 
        g.seek(-2, os.SEEK_CUR) 
    print(g.readline().decode())
print(time.time() - t0)    

速度慢可能是因为循环中调用了很多seek

所以这个只有一个 seek 的解决方案有效:

with gzip.open(f, 'rb') as g:
    g.seek(-1000, os.SEEK_END)  # go 1000 bytes before end
    l = g.readlines()[-1].decode() # the last line

注意:

  • g.readlines() 在这里很快,因为它只将最后 1000 个字节拆分为行
  • 根据您的文件中可能出现的最长行更改 1000

仍在寻找更好的解决方案。这是链接但没有给出获取最后一行的真正解决方案:Lazy Method for Reading Big File in Python?

如果您无法控制 gzip 文件的生成,那么在不解码所有行的情况下就无法读取未压缩数据的最后一行。所需时间为 O(n),其中 n 是文件的大小。没有办法让它成为 O(1).

如果您确实控制了压缩端,那么您可以创建一个便于随机访问的 gzip 文件,您还可以跟踪随机访问入口点以启用跳转到文件末尾。