Як я можу розпакувати потік gzip за допомогою zlib?


108

Файли формату Gzip (створені, наприклад, з gzipпрограмою) використовують алгоритм стиснення "спуску", який є тим же алгоритмом стиснення, що і zlib . Однак при використанні zlib для надуття стиснутого файлу gzip бібліотека повертає a Z_DATA_ERROR.

Як я можу використовувати zlib для розпакування файлу gzip?

Відповіді:


118

Щоб розпакувати файл в форматі GZIP з Zlib, виклик inflateInit2з windowBitsпараметром як 16+MAX_WBITS, як це:

inflateInit2(&stream, 16+MAX_WBITS);

Якщо цього не зробити, zlib поскаржиться на неправильний формат потоку. За замовчуванням zlib створює потоки із заголовком zlib, а on inflate не розпізнає різні заголовки gzip, якщо ви цього не скажете. Хоча це задокументовано, починаючи з версії 1.2.1 zlib.hзаголовного файлу, це не знаходиться в керівництві zlib . З файлу заголовка:

windowBitsможе також бути більше 15 для необов'язкового декодування gzip. Додайте 32, щоб windowBitsувімкнути декодування zlib та gzip з автоматичним виявленням заголовка, або додайте 16 для декодування лише формату gzip (формат zlib повернеться a Z_DATA_ERROR). Якщо потік gzip декодується, strm->adlerце crc32 замість adler32.


35
У пітоні:zlib.decompress(data, 15 + 32)
Роман Старков

3
Дякую, це дуже засмутило, поки я не знайшов цю посаду.
Олексій

Ого, це питання 2009 року. Дякуємо @Greg Hewgill
YuAn Shaolin Maculelê Lai

Можливо, ви можете надати деякі рекомендації щодо ітеративної декомпресії потоку gzip. Декомпресія gzip з одним знімком, де вихідний потік та розмір повинні бути фіксованими та достатніми для зберігання всього декомпресованого виводу. Це значення залежить від ефективності декомпресії gzip, яка може змінюватися залежно від ентропії даних. Чи є спосіб динамічно виділити більше місця для виводу буфера при необхідності? Спасибі
Zohar81

104

пітон

zlibбібліотека підтримує :

  • RFC 1950 ( zlibстислий формат)
  • RFC 1951 ( deflateстислий формат)
  • RFC 1952 ( gzipстислий формат)

Модуль 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безпосередньо використовувати модуль; але , будь ласка , пам'ятайте , що під капотом , gzipвикористання zlib.

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

3
чому цього золота немає на документах саме цього формату?
Рамон Мораес

будь-ласка, надішліть запит на витяг / патч проти cpython, використовуючи будь-яку з цієї відповіді.
dnozay

чудова відповідь для рядків, будь-яка ідея, як це зробити для потоку, не читаючи весь файл в пам'яті?
Josh J

Дякую. Я можу вирішити свою проблему декомпресії у своєму вихідному коді за допомогою вашої відповіді.
Віфлі

неймовірно, це золотий самородок .. однак я не можу не відчути, що вони є рівнозначними "магічним числам"? де в документації це згадується? Я дивився, але, мабуть, насправді не перевірив достатньо важко .. Також, позначення я не повністю дотримуюся. Що означає | означає, це необов’язково? а чому дефляція від’ємна .. це MAX_WBITS константа .. 🙁
m1nkeh

3

Будова zlib та gzip різна. zlib використовує RFC 1950, а gzip використовує RFC 1952 , тому мають різні заголовки, але решта мають однакову структуру і слідкує за RFC 1951 .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.