Bagaimana cara mendekompresi aliran gzip dengan zlib?

108

File berformat Gzip (dibuat dengan gzipprogram, misalnya) menggunakan algoritma kompresi "deflate", yang merupakan algoritma kompresi yang sama dengan yang digunakan zlib . Namun, saat menggunakan zlib untuk memekarkan file yang dikompresi dengan gzip, pustaka mengembalikan file Z_DATA_ERROR.

Bagaimana cara menggunakan zlib untuk mendekompresi file gzip?

Greg Hewgill
sumber

Jawaban:

118

Untuk mendekompresi file berformat gzip dengan zlib, panggil inflateInit2dengan windowBitsparameter sebagai 16+MAX_WBITS, seperti ini:

inflateInit2(&stream, 16+MAX_WBITS);

Jika Anda tidak melakukannya, zlib akan mengeluh tentang format streaming yang buruk. Secara default, zlib membuat aliran dengan header zlib, dan pada inflate tidak mengenali header gzip yang berbeda kecuali Anda memberitahunya. Meskipun ini didokumentasikan mulai dari versi 1.2.1 dari zlib.hfile header, ini tidak ada di manual zlib . Dari file header:

windowBitsjuga bisa lebih besar dari 15 untuk dekode gzip opsional. Tambahkan 32 ke windowBitsuntuk mengaktifkan dekode zlib dan gzip dengan deteksi header otomatis, atau tambahkan 16 untuk mendekode hanya format gzip (format zlib akan mengembalikan a Z_DATA_ERROR). Jika aliran gzip sedang didekodekan, itu strm->adleradalah crc32, bukan adler32.

Greg Hewgill
sumber
35
Dengan python:zlib.decompress(data, 15 + 32)
Roman Starkov
3
Terima kasih, ini sangat membuat frustrasi sampai saya menemukan posting ini.
Alex
Wow, ini pertanyaan tahun 2009. Terima kasih
@Greg
Mungkin Anda dapat memberikan beberapa pedoman untuk dekompresi berulang aliran gzip. Dalam dekompresi gzip sekali pakai di mana aliran dan ukuran keluaran Anda harus tetap dan cukup untuk menyimpan seluruh keluaran yang didekompresi. Nilai ini bergantung pada efektivitas dekompresi gzip yang dapat bervariasi sesuai dengan entropi data. Apakah ada cara untuk mengalokasikan lebih banyak ruang secara dinamis ke buffer keluaran saat diperlukan? Terima kasih
Zohar81
104

python

zlibdukungan perpustakaan :

zlibModul python juga akan mendukung ini.

memilih windowBits

Tetapi zlibdapat mendekompresi semua format itu:

  • ke (de-) deflateformat kompres , gunakanwbits = -zlib.MAX_WBITS
  • ke (de-) zlibformat kompres , gunakanwbits = zlib.MAX_WBITS
  • ke (de-) gzipformat kompres , gunakanwbits = zlib.MAX_WBITS | 16

Lihat dokumentasi di http://www.zlib.net/manual.html#Advanced (bagian inflateInit2)

contoh

data uji:

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

tes yang jelas untuk zlib:

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

tes untuk 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'

tes untuk 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'

data juga kompatibel dengan gzipmodul:

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

deteksi tajuk otomatis (zlib atau gzip)

menambahkan 32ke windowBitsakan memicu deteksi header

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

menggunakan gzipsebagai gantinya

Untuk gzipdata dengan header gzip Anda dapat menggunakan gzipmodul secara langsung; tapi harap diingat bahwa di bawah tenda , gzipgunakan zlib.

fh = gzip.open('abc.gz', 'rb')
cdata = fh.read()
fh.close()
tidak tahu
sumber
3
mengapa kepingan emas ini tidak ada di dokumen dalam format persis seperti ini?
Ramon Moraes
jangan ragu untuk mengirim permintaan pull / patch terhadap cpython menggunakan salah satu jawaban ini.
dnozay
jawaban yang bagus untuk string, ada ide bagaimana melakukan ini untuk streaming tanpa membaca seluruh file ke dalam memori?
Josh J
Terima kasih. Saya dapat menyelesaikan masalah dekompresi saya di kode sumber saya dengan jawaban Anda.
Bethlee
luar biasa, ini adalah bongkahan emas .. namun saya tidak bisa tidak merasa ini sama saja dengan 'angka ajaib'? di mana dalam dokumentasi ini disebutkan? saya melihat, tetapi pasti benar-benar tidak memeriksa cukup keras .. juga, notasi saya tidak sepenuhnya ikuti. Apa | Maksudnya, apakah itu opsional? dan mengapa mengempis negatif .. apakah MAX_WBITS konstan .. 🙁
m1nkeh
3

Struktur zlib dan gzip berbeda. zlib menggunakan RFC 1950 dan gzip menggunakan RFC 1952 , jadi memiliki header yang berbeda tetapi sisanya memiliki struktur yang sama dan mengikuti RFC 1951 .

josep fon
sumber