2009-11-14 127 views
7

所以问题来了。我有大约60KB的sample.gz文件。我想解压缩这个文件的第一个2000字节。我正在运行CRC检查失败的错误,我猜是因为gzip CRC字段出现在文件的末尾,并且它需要整个gzip文件进行解压缩。有没有办法解决这个问题?我不关心CRC检查。即使由于CRC错误而无法解压缩,也没关系。有没有办法解决这个问题,并解压缩部分.gz文件?使用python解压缩.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的头?

+0

因为我很感兴趣,第一个可能的压缩数据的4K。 – user210126 2009-11-14 00:22:38

回答

11

我看来,你需要寻找到Python zlib库,而不是

的gzip格式依赖于zlib的,但是引入了AA文件级压缩概念利用CRC校验一起,而这似乎是你不想要的东西/目前需要。

例如见这些code snippets from Dough Hellman

编辑:上Doubh赫尔曼的网站的代码只显示如何压缩或解压缩的zlib。如上所述,GZIP是“带有信封的zlib”,您需要在获取zlib压缩数据本身之前解码envellope。这里的更多信息去了解它,它真的没有那么复杂:

  • 看到RFC 1952有关GZIP格式的详细信息
  • 此格式的10个字节的头,其次是可选的,非压缩的元素,如文件名或注释,然后是zlib压缩数据,后面跟着一个CRC-32(正好是“Adler32”CRC)。
  • 通过使用Python's struct module,解析头应该是比较简单
  • zlib数据序列(或它的第一个几千字节,因为这是你想要做什么),然后可以用Python的zlib的模块进行解压缩,如图所示上面的例子
  • 可能的问题处理:如果GZip存档中有多个文件,并且第二个文件在几千字节的块内启动,我们希望解压缩。

对不起,既不提供一个简单的程序,也不是一个准备好的代码片段,但是用上面的指示来解码文件应该是相对快速和简单的。

+0

@mjv ... 哪个特定的代码段适用于上面的示例。我浏览了链接并阅读了使用Streams。它没有任何地方说它使用gzip流。我认为这适用于zlib流(已经用zlib流测试过) – user210126 2009-11-14 00:35:30

+0

@unknown:检查我的编辑;代码片段涉及到纯zlib的压缩/解压缩。 GZip格式意味着在找到可以如图所示解压缩的zlip“有效载荷”之前,先解析一个小的未压缩标头。 – mjv 2009-11-14 05:35:39

8

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

当然要解压缩文件,并停止当你解压缩尽可能多的文件,因为你需要,是这样的:

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

AFAIK,这不会导致读取整个文件。它只会读取所需的第一个4000字节。

+0

f.read(2000)将读取解压缩数据的前2000字节。我对2000字节的压缩数据感兴趣。 – user210126 2009-11-14 00:25:00

+0

为什么?你的申请究竟是什么? – rjmunro 2009-11-14 00:27:22

+0

:-) 我想在数据的第一个4k中找到字符串“xyz”。假设我解压缩2K的压缩数据,并且解压缩数据为4K,我可以在这个4k中搜索/ grep作为字符串。所有的搜索代码已经到位了.. – user210126 2009-11-14 00:31:41

2

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

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

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

def _read_eof(self): 
    pass 

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

我知道这是一个蛮力解决方案,但它使用像读取数据夹的压缩模块,通过吸盘从压缩文件节省了大量的时间来改写自己的一些低级别的方法和逐行提取数据,其中大部分数据已存在于gzip模块中。

贾敏

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