我想要了解向后读取gzip文件的最有效(速度和性能)方法,而不将整个文件的内容加载到内存中。
这是我目前所做的,但对于非常大的文件效率不高:
file = 'huge_file.log.gz'
import gzip
if file.endswith('gz'):
f = gzip.open(file)
# reverse the file contents
reverse_file_list = reversed(f.read().decode('utf-8').split('\n'))
我看到stackoverflow和codestate中有一些解决方案执行否定搜索但是在文件以二进制模式打开时不支持否定搜索,如gzip.open
链接: Most efficient way to search the last x lines of a file in python
http://code.activestate.com/recipes/439045/
所以解决方案因我想要完成的事情而失败。
答案 0 :(得分:1)
唯一的解决方案可能是将文件解压缩到磁盘并反转行顺序。它使用两倍的磁盘空间,但不使用内存。
您可以使用以下方法立即完成这两个步骤:
gzip -cd huge_file.log.gz | tac > huge_file.log.reversed
然后您可以正常阅读和处理。
答案 1 :(得分:1)
真的没有好办法。 gzip(deflate)压缩数据格式在使用霍夫曼代码和在之前的32K中使用匹配字符串时都是固有的串行。
如果无法将其全部存入内存,则需要a)将其解压缩到磁盘,并使用未压缩格式的搜索来反转它,或者b)通过gzip文件执行一次解压缩传递,从而有效地创建随机访问小块的入口点,小到足以保留在内存中,然后向后执行第二次解压缩,反转每个块。
a)可以使用tac完成,如@ Jud的回答所示,因为tac会在磁盘上创建一个临时文件来保存未压缩的内容。
b)很复杂,需要深入了解放气格式。它还要求您为内存或磁盘上的每个入口点保存32K的历史记录。
答案 2 :(得分:0)
不幸的是,您必须从头开始解析gz文件,并且可能需要花时间将它们全部解析到最后。我使用一个列表缓冲区,如果reverse = True并且已达到BSIZE,则只弹出第一个项目,它将始终保存文件的最后一次BSIZE匹配并且在一次传递中:
BSIZE = 100; searchstr= "match in gzfile"; n = 0; buffer = []; reversed = True
# gzf is an *.gz file in a directory
with gzip.open(files['path'] + '/' + gzf, 'rt') as f:
for line in f:
if re.search(searchstr, line):
n += 1
buffer.append(line.strip())
if n >= BSIZE and not reversed:
break
elif n >= BSIZE:
buffer.pop(0)