如果不了解您实际处理的文件格式的更具体知识,很难说很多,但很明显,您的算法对子字符串的处理是二次的——当您拥有数以万计的子字符串时,这不是一件好事。那么让我们看看我们所知道的:
你说供应商说他们是
使用标准的 zlib 压缩库。这些是构建 gzip 实用程序的相同压缩例程。
由此我们可以得出结论,组件流是原始 zlib 格式,并且没有封装在 gzip 包装器(或 PKZIP 存档或其他任何东西)中。ZLIB 格式的权威文档在这里:https ://www.rfc-editor.org/rfc/rfc1950
因此,让我们假设您的文件与您描述的完全一样:一个 32 字节的标头,后面是连接在一起的原始 ZLIB 流,中间没有任何其他内容。(编辑:毕竟不是这样)。
Python 的zlib 文档提供了一个Decompress
实际上非常适合翻阅文件的类。它包括一个属性unused_data
,其文档明确指出:
确定一串压缩数据在哪里结束的唯一方法是实际解压缩它。这意味着当压缩数据包含在较大文件的一部分时,您只能通过读取数据并将其后跟一些非空字符串提供给解压缩对象的 decompress() 方法来找到它的结尾,直到不再使用未使用的数据属性空字符串。
因此,您可以这样做:编写一个循环,一次读取data
一个块(甚至不需要将整个 800MB 文件读入内存)。将每个块推送到Decompress
对象,并检查unused_data
属性。当它变成非空时,你就有了一个完整的对象。将其写入磁盘,创建一个新的解压缩对象并使用unused_data
最后一个对象初始化 iw。这可能有效(未经测试,因此请检查正确性)。
编辑:由于您的数据流中确实有其他数据,因此我添加了一个与下一个 ZLIB 开始对齐的例程。您需要找到并填写在数据中标识 ZLIB 流的两字节序列。(请随意使用您的旧代码来发现它。)虽然通常没有固定的 ZLIB 标头,但对于每个流来说它应该是相同的,因为它由协议选项和标志组成,对于整个运行来说它们可能是相同的。
import zlib
# FILL IN: ZHEAD is two bytes with the actual ZLIB settings in the input
ZHEAD = CMF+FLG
def findstart(header, buf, source):
"""Find `header` in str `buf`, reading more from `source` if necessary"""
while buf.find(header) == -1:
more = source.read(2**12)
if len(more) == 0: # EOF without finding the header
return ''
buf += more
offset = buf.find(header)
return buf[offset:]
然后,您可以前进到下一个流的开头。我添加了一个try
/except
对,因为相同的字节序列可能出现在流之外:
source = open(datafile, 'rb')
skip_ = source.read(32) # Skip non-zlib header
buf = ''
while True:
decomp = zlib.decompressobj()
# Find the start of the next stream
buf = findstart(ZHEAD, buf, source)
try:
stream = decomp.decompress(buf)
except zlib.error:
print "Spurious match(?) at output offset %d." % outfile.tell(),
print "Skipping 2 bytes"
buf = buf[2:]
continue
# Read until zlib decides it's seen a complete file
while decomp.unused_data == '':
block = source.read(2**12)
if len(block) > 0:
stream += decomp.decompress(block)
else:
break # We've reached EOF
outfile.write(stream)
buf = decomp.unused_data # Save for the next stream
if len(block) == 0:
break # EOF
outfile.close()
PS 1. 如果我是你,我会将每个 XML 流写入一个单独的文件。
PS 2. 您可以在文件的第一个 MB 上测试您所做的任何事情,直到获得足够的性能。