zlibでgzipストリームを解凍するにはどうすればよいですか?


108

gzip形式のファイル(gzipプログラムで作成されたファイルなど)は、「deflate」圧縮アルゴリズムを使用します。これは、zlibが使用するものと同じ圧縮アルゴリズムです。ただし、zlibを使用してgzip圧縮ファイルを拡張すると、ライブラリはを返しますZ_DATA_ERROR

zlibを使用してgzipファイルを解凍するにはどうすればよいですか?

回答:


118

zlibのではgzip形式のファイルを解凍するには、呼び出しinflateInit2windowBitsパラメータとして16+MAX_WBITS、このように、:

inflateInit2(&stream, 16+MAX_WBITS);

これを行わないと、zlibは不正なストリーム形式について文句を言うでしょう。デフォルトでは、zlibはzlibヘッダーを使用してストリームを作成します。指示がない限り、inflateは異なるgzipヘッダーを認識しません。これはzlib.hヘッダーファイルのバージョン1.2.1から文書化されていますが、zlibマニュアルには含まれていません。ヘッダーファイルから:

windowBitsオプションのgzipデコードでは、15より大きくすることもできます。32を追加するwindowBitsと、zlibとgzipのデコードが自動ヘッダー検出で有効になります。16を追加すると、gzip形式のみがデコードされます(zlib形式ではが返されますZ_DATA_ERROR)。gzipストリームがデコードされている場合strm->adlerは、adler32ではなくcrc32です。


35
Pythonの場合:zlib.decompress(data, 15 + 32)
Roman Starkov

3
ありがとう、私がこの投稿を見つけるまで、これは非常にイライラしました。
Alex

わあ、これは2009年の質問です。ありがとう@Greg Hewgill
YuAn ShaolinMaculelêLai

おそらく、gzipストリームを繰り返し解凍するためのガイドラインを提供できます。ワンショットgzip解凍では、出力ストリームとサイズが固定され、解凍された出力全体を格納するのに十分である必要があります。この値は、データエントロピーによって異なる可能性のあるgzip解凍の有効性に依存します。必要に応じて、出力バッファーに動的により多くのスペースを割り当てる方法はありますか?ありがとう
Zohar81

103

python

zlibライブラリは以下をサポートします

python zlibモジュールもこれらをサポートします。

windowBitsの選択

しかし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代わりに使用

gzipgzipヘッダとデータを使用できgzip、直接モジュールを。ただし、内部gzipは、を使用していることを忘れないでくださいzlib

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

3
なぜこの金貨がこの正確なフォーマットのドキュメントに載っていないのですか?
Ramon Moraes

この回答のいずれかを使用して、cpythonに対してプルリクエスト/パッチを送信してください。
dnozay 2016

文字列の素晴らしい答え、ファイル全体をメモリに読み込まずにストリームに対してこれを行う方法はありますか?
Josh J

ありがとうございました。私はソースコードの解凍問題をあなたの答えで解決できます。
Bethlee 2018年

信じられないほど、これは金のナゲットです。しかし、これらは「マジックナンバー」に等しいと感じざるを得ませんか?ドキュメントのどこにこれが記載されていますか?私は見ましたが、本当に十分にチェックしていなかったに違いありません。また、私が完全に従わない表記法もあります。何を| つまり、それはオプションですか?そしてなぜデフレート負のは...ある一定のMAX_WBITS ..です🙁
m1nkeh

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.