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

使用python解压.gz文件的一部分,python,gzip,zlib,Python,Gzip,Zlib,这就是问题所在。我有sample.gz文件,大约60KB大小。我想解压缩这个文件的前2000个字节。我遇到了CRC检查失败的错误,我想是因为gzip CRC字段出现在文件的末尾,它需要解压整个gzip文件。有没有办法绕过这个问题?我不在乎CRC检查。即使我因为坏的CRC而无法解压,也没关系。有没有办法绕过这个问题并解压缩部分.gz文件 到目前为止,我掌握的代码是 import gzip import time import StringIO file = open('sample.gz', '

这就是问题所在。我有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头?

看来您需要查看库

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

例如,参见这些

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

  • 有关GZIP格式的详细信息,请参阅
  • 这种格式以一个10字节的头开始,后面是可选的非压缩元素,如文件名或注释,后面是zlib压缩数据,后面是CRC-32(确切地说是“Adler32”CRC)
  • 通过使用,解析标头应该相对简单
  • 然后可以使用python的zlib模块对zlib序列(或者它的前几千个字节,因为这是您想要做的)进行解压缩,如上面的示例所示
  • 可能需要处理的问题:如果GZip存档中有多个文件,并且如果第二个文件在几千字节的块内开始,我们希望解压缩

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

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

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

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

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

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

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

但在某些情况下,如处理流或没有正确CRC的.gz文件(我的问题),IOError(“CRC检查失败”)将由_read_eof()引发。因此,我尝试修改gzip模块来禁用CRC检查,最终这个问题消失了

def _read_eof(self):
    pass

我知道这是一个蛮力解决方案,但是使用zip模块重写一些低级方法可以节省很多时间,比如从压缩文件中逐个读取数据,并逐行提取数据,其中大部分都出现在gzip模块中


Jamin

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

关键是欺骗gzip跳过验证。通过修改gzip源代码可以做到这一点,但不必走那么远,简单的猴子补丁就可以了。我编写此上下文管理器是为了临时替换
gzip.gzip文件。解压部分文件时,读取\u 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()

因为我对压缩数据的第一个可能是4k感兴趣。这里的f.read(2000)将读取解压缩数据的前2000字节。我对前2000字节的压缩数据感兴趣。为什么?你的应用程序到底是什么?:-)我试图在第一个4k数据中找到字符串“xyz”。假设我解压缩了2K的gzip数据,并使用4K的解压缩数据登陆,我可以在这个4K中搜索/grep字符串。所有搜索代码都已准备就绪。如果要搜索前4k未压缩数据,请搜索前4k未压缩数据,就像我在回答中所做的那样(可能将4000更改为4096)。不要试图猜测2k将解压缩到4k。可能不会。它可能只解压到2k,也可能解压到几兆字节。这太完美了。非常感谢你!不需要肮脏的黑客。@mjv。。。哪个特定的代码段适用于上面的示例。我浏览了链接并阅读了《使用流工作》。它没有声明它使用gzip流。我假设这适用于zlib流(已经用zlib流测试过)@unknown:检查我的编辑;这些代码片段与对纯zlib进行压缩/解压缩有关。GZip格式意味着首先解析一个小的未压缩头,然后再找到它的zlip“有效负载”,如图所示,它可以被解压缩。