2013-11-15 65 views
1

我想要了解什么是最有效(速度和性能)的方式来向后读取gzip文件,而无需将整个文件的内容加载到内存中。反向读取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')) 

我看到有在计算器和codestate一些解决方案,这样做的负面寻求反而不利寻求在文件中不支持以二进制方式打开与gzip.open

链接: Most efficient way to search the last x lines of a file in python

http://code.activestate.com/recipes/439045/

所以解决方案失败了,我想完成。

回答

1

真的没有一个好方法。 gzip(deflate)压缩数据格式在使用霍夫曼代码和在先前的32K中使用匹配字符串时固有地是串行的。

如果你不能把它全部放到内存中,你需要a)将它解压缩到磁盘上,并使用未压缩表单上的查找来反转它,或者b)通过创建一个解压缩文件来有效地创建gzip文件随机访问入口点足够小以保留在内存中,然后执行第二次解压向后传递,反转每个块。 a)可以用tac完成,正如@Jud的答案中所建议的,因为tac将在磁盘上创建一个临时文件来保存未压缩的内容。 b)复杂,需要对放气格式有深入的了解。它还要求您为每个入口点保存32K的历史记录,无论是在内存中还是在磁盘上。

1

唯一的解决方案可能是将文件解压缩到磁盘并反转行顺序。它使用磁盘空间的两倍,但不是内存。

您可以一次同时完成这些步骤:

gzip -cd huge_file.log.gz | tac > huge_file.log.reversed 

然后就可以正常阅读和处理。

+0

+1使用'TAC ' –

0

不幸的是,您必须从头开始解析gz文件,并且可能会耗费时间将它们全部解析到最后。我用一个列表缓冲区,如果反向= 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)