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

2024-04-24 10:23:36 发布

您现在位置:Python中文网/ 问答频道 /正文

这就是问题所在。我有sample.gz文件,大小约为60KB。我想解压缩这个文件的前2000字节。我遇到了CRC check failed错误,我猜是因为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头?


Tags: 文件inpyimportreadchecklinefile
3条回答

我觉得你应该查一下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存档中有多个文件,并且如果第二个文件在几千字节的块中开始,我们希望解压缩。

很抱歉,我们既没有提供简单的过程,也没有提供现成的代码片段,但是,使用上面的指示对文件进行解码应该比较快速和简单。

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

当然,您希望解压缩文件,并在解压缩了所需的文件量后停止,例如:

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

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

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()

相关问题 更多 >