【问题标题】:How can I decompress a gzip stream with zlib?如何使用 zlib 解压缩 gzip 流?
【发布时间】:2010-12-22 18:16:13
【问题描述】:

Gzip 格式文件(例如使用gzip 程序创建)使用“deflate”压缩算法,该算法与zlib 使用的压缩算法相同。但是,当使用 zlib 对 gzip 压缩文件进行膨胀时,该库会返回一个Z_DATA_ERROR

如何使用 zlib 解压 gzip 文件?

【问题讨论】:

    标签: gzip zlib inflate


    【解决方案1】:

    要使用 zlib 解压 gzip 格式的文件,调用 inflateInit2 并将 windowBits 参数设为 16+MAX_WBITS,如下所示:

    inflateInit2(&stream, 16+MAX_WBITS);
    

    如果您不这样做,zlib 将抱怨流格式错误。默认情况下,zlib 创建带有 zlib 标头的流,并且在 inflate 上不会识别不同的 gzip 标头,除非您告诉它。尽管从 zlib.h 头文件的 1.2.1 版开始记录了这一点,但它不在 zlib manual 中。从头文件:

    windowBits 也可以大于 15 用于可选的 gzip 解码。添加 32 到 windowBits 以启用带有自动标头的 zlib 和 gzip 解码 检测,或添加 16 以仅解码 gzip 格式(zlib 格式将 返回Z_DATA_ERROR)。如果正在解码 gzip 流,strm->adler 是 一个 crc32 而不是 adler32。

    【讨论】:

    • 在python中:zlib.decompress(data, 15 + 32)
    • 谢谢,在我找到这篇文章之前,这非常令人沮丧。
    • 哇,这是 2009 年的问题。谢谢@Greg Hewgill
    • 或许可以提供一些gzip流迭代解压的指导。在一次性 gzip 解压缩中,您的输出流和大小应该是固定的,并且足以存储整个解压缩的输出。该值取决于 gzip 解压缩效果,该效果会根据数据熵而变化。有没有办法在需要时为输出缓冲区动态分配更多空间?谢谢
    • 我不知道这将如何工作。但它确实有效。
    【解决方案2】:

    蟒蛇

    zlib library supports:

    python zlib 模块也将支持这些。

    选择窗口位

    但是zlib 可以解压所有这些格式:

    • 要(去)压缩deflate 格式,使用wbits = -zlib.MAX_WBITS
    • 要(去)压缩zlib 格式,使用wbits = zlib.MAX_WBITS
    • 要(去)压缩gzip 格式,使用wbits = zlib.MAX_WBITS | 16

    参见http://www.zlib.net/manual.html#Advanced 中的文档(inflateInit2 部分)

    示例

    测试数据:

    >>> deflate_compress = zlib.compressobj(9, zlib.DEFLATED, -zlib.MAX_WBITS)
    >>> zlib_compress = zlib.compressobj(9, zlib.DEFLATED, zlib.MAX_WBITS)
    >>> gzip_compress = zlib.compressobj(9, zlib.DEFLATED, zlib.MAX_WBITS | 16)
    >>> 
    >>> text = '''test'''
    >>> deflate_data = deflate_compress.compress(text) + deflate_compress.flush()
    >>> zlib_data = zlib_compress.compress(text) + zlib_compress.flush()
    >>> gzip_data = gzip_compress.compress(text) + gzip_compress.flush()
    >>> 
    

    zlib 的明显测试:

    >>> zlib.decompress(zlib_data)
    'test'
    

    测试deflate

    >>> zlib.decompress(deflate_data)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    zlib.error: Error -3 while decompressing data: incorrect header check
    >>> zlib.decompress(deflate_data, -zlib.MAX_WBITS)
    'test'
    

    测试gzip

    >>> zlib.decompress(gzip_data)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    zlib.error: Error -3 while decompressing data: incorrect header check
    >>> zlib.decompress(gzip_data, zlib.MAX_WBITS|16)
    'test'
    

    数据也兼容gzip模块:

    >>> import gzip
    >>> import StringIO
    >>> fio = StringIO.StringIO(gzip_data)
    >>> f = gzip.GzipFile(fileobj=fio)
    >>> f.read()
    'test'
    >>> f.close()
    

    自动标头检测(zlib 或 gzip)

    32 添加到windowBits 将触发标头检测

    >>> zlib.decompress(gzip_data, zlib.MAX_WBITS|32)
    'test'
    >>> zlib.decompress(zlib_data, zlib.MAX_WBITS|32)
    'test'
    

    改用gzip

    对于带有 gzip 标头的 gzip 数据,您可以直接使用 gzip 模块;但是please remember that under the hoodgzip 使用zlib

    fh = gzip.open('abc.gz', 'rb')
    cdata = fh.read()
    fh.close()
    

    【讨论】:

    • 为什么这块黄金不在这种格式的文档上?
    • 请随时使用任何此答案发送针对 cpython 的拉取请求/补丁。
    • 字符串的好答案,知道如何在不将整个文件读入内存的情况下对流执行此操作吗?
    • 谢谢。我可以用你的答案在我的源代码中解决我的解压问题。
    • @m1nkeh:在 Python 中,与大多数(如果不是全部)语言一样,| 是按位-OR 运算符,如+-* 等等在。在实践中,它用于在数字中“设置位”。所以zlib.MAX_WBITS | 16 的意思是:在数字zlib.MAX_WBITS 中,“打开”设置为 16 的位(它是 2 的幂,是单个位)。
    【解决方案3】:

    zlib 和 gzip 的结构不同。 zlib 使用RFC 1950,gzip 使用RFC 1952, 所以有不同的标题,但其余的具有相同的结构并遵循RFC 1951

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-30
      • 1970-01-01
      相关资源
      最近更新 更多