使用python解压缩.gz文件的一部分

时间:2009-11-14 00:14:38

标签: python gzip zlib

所以这就是问题所在。我有sample.gz文件,大小约为60KB。我想解压缩此文件的前2000个字节。我正在运行CRC校验失败错误,我猜因为gzip CRC字段出现在文件的末尾,它需要整个gzip文件进行解压缩。有办法解决这个问题吗?我不关心CRC检查。即使我因CRC错误而无法解压缩,也没关系。有没有办法绕过这个并解压缩部分.gz文件?

到目前为止我的代码是

import gzip
import time
import StringIO

file = open('sample.gz', 'rb')
mybuf = MyBuffer(file)
mybuf = StringIO.StringIO(file.read(2000))
f = gzip.GzipFile(fileobj=mybuf)
data = f.read()
print data

遇到的错误是

File "gunzip.py", line 27, in ?
    data = f.read()
File "/usr/local/lib/python2.4/gzip.py", line 218, in read
  self._read(readsize)
File "/usr/local/lib/python2.4/gzip.py", line 273, in _read
  self._read_eof()
File "/usr/local/lib/python2.4/gzip.py", line 309, in _read_eof
  raise IOError, "CRC check failed"
IOError: CRC check failed

还有什么方法可以使用zlib模块执行此操作并忽略gzip标头?

4 个答案:

答案 0 :(得分:13)

gzip模块的问题不在于它无法解压缩部分文件,只有在尝试验证解压缩内容的校验和时才会发生错误。 (原始校验和存储在压缩文件的末尾,因此验证永远不会使用部分文件。)

关键是欺骗gzip跳过验证。 answer by caesar0301通过修改gzip源代码来实现这一点,但是没有必要这么做,简单的猴子修补就行了。我编写了这个上下文管理器,在我解压缩部分文件时临时替换gzip.GzipFile._read_eof

import contextlib

@contextlib.contextmanager
def patch_gzip_for_partial():
    """
    Context manager that replaces gzip.GzipFile._read_eof with a no-op.

    This is useful when decompressing partial files, something that won't
    work if GzipFile does it's checksum comparison.

    """
    _read_eof = gzip.GzipFile._read_eof
    gzip.GzipFile._read_eof = lambda *args, **kwargs: None
    yield
    gzip.GzipFile._read_eof = _read_eof

示例用法:

from cStringIO import StringIO

with patch_gzip_for_partial():
    decompressed = gzip.GzipFile(StringIO(compressed)).read()

答案 1 :(得分:12)

我似乎需要查看Python zlib库而不是

GZIP格式依赖于zlib,但引入了文件级压缩概念以及CRC校验,这似乎是您目前不想要/不需要的。

例如,参见code snippets from Dough Hellman

编辑:Doubh Hellman网站上的代码仅显示如何使用zlib进行压缩或解压缩。如上所述,GZIP是“带信封的zlib”,在获取zlib压缩数据本身之前,您需要解码envellope。这里有更多关于它的信息,它真的不那么复杂:

  • 有关GZIP格式的详细信息,请参阅RFC 1952
  • 此格式以10字节标头开头,后跟可选的非压缩元素,如文件名或注释,后跟zlib压缩数据,后跟CRC-32(恰好是“Adler32”CRC) )。
  • 使用Python's struct module,解析标题应该相对简单
  • 然后可以使用python的zlib模块解压缩zlib序列(或其前几千个字节,因为这是你想要做的),如上面的例子所示
  • 可能遇到的问题:如果GZip存档中有多个文件,并且第二个文件在几千字节的块内启动,我们希望解压缩。

很抱歉既不提供简单的程序也不提供随时可用的代码段,但是使用上述指示对文件进行解码应该相对快速和简单。

答案 2 :(得分:10)

我看不出你想要解压缩前2000个压缩字节的任何可能原因。根据数据的不同,这可能会解压缩到任意数量的输出字节。

当然,您要解压缩文件,并在您根据需要解压缩文件时停止,例如:

f = gzip.GzipFile(fileobj=open('postcode-code.tar.gz', 'rb'))
data = f.read(4000)
print data

AFAIK,这不会导致整个文件被读取。它只能读取获得前4000个字节所需的数量。

答案 3 :(得分:2)

当我使用我的python脚本读取由Linux下的gzip工具生成的压缩文件并且原始文件丢失时,我也遇到了这个问题。

通过阅读Python gzip.py的实现,我发现gzip.GzipFile有类似的File类方法,并利用python zip模块来处理数据解压缩。同时,还会出现_read_eof()方法来检查每个文件的CRC。

但在某些情况下,如处理Stream或.gz文件而没有正确的CRC(我的问题),_read_eof()会引发IOError(“CRC check failed”)。因此,我尝试修改gzip模块以禁用CRC校验,最后这个问题就消失了。

def _read_eof(self):
    pass

https://github.com/caesar0301/PcapEx/blob/master/live-scripts/gzip_mod.py

我知道这是一个蛮力的解决方案,但它可以节省很多时间来使用zip模块重写自己的一些低级方法,比如从压缩文件读取chuck数据并逐行提取数据,大多数它存在于gzip模块中。

贾敏