【发布时间】:2010-12-22 18:16:13
【问题描述】:
Gzip 格式文件(例如使用gzip 程序创建)使用“deflate”压缩算法,该算法与zlib 使用的压缩算法相同。但是,当使用 zlib 对 gzip 压缩文件进行膨胀时,该库会返回一个Z_DATA_ERROR。
如何使用 zlib 解压 gzip 文件?
【问题讨论】:
Gzip 格式文件(例如使用gzip 程序创建)使用“deflate”压缩算法,该算法与zlib 使用的压缩算法相同。但是,当使用 zlib 对 gzip 压缩文件进行膨胀时,该库会返回一个Z_DATA_ERROR。
如何使用 zlib 解压 gzip 文件?
【问题讨论】:
要使用 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。
【讨论】:
zlib.decompress(data, 15 + 32)
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()
将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 hood、gzip 使用zlib。
fh = gzip.open('abc.gz', 'rb')
cdata = fh.read()
fh.close()
【讨论】:
| 是按位-OR 运算符,如+、-、* 等等在。在实践中,它用于在数字中“设置位”。所以zlib.MAX_WBITS | 16 的意思是:在数字zlib.MAX_WBITS 中,“打开”设置为 16 的位(它是 2 的幂,是单个位)。