Wie kann ich einen gzip-Stream mit zlib dekomprimieren?


108

Dateien im Gzip-Format ( gzipzum Beispiel mit dem Programm erstellt ) verwenden den Komprimierungsalgorithmus "deflate", der der gleiche Komprimierungsalgorithmus ist wie der von zlib . Wenn Sie jedoch zlib zum Aufblasen einer gzip-komprimierten Datei verwenden, gibt die Bibliothek a zurück Z_DATA_ERROR.

Wie kann ich mit zlib eine gzip-Datei dekomprimieren?

Antworten:


118

Um eine Datei im GZIP-Format mit zlib zu dekomprimieren, rufen Sie inflateInit2den folgenden windowBitsParameter auf 16+MAX_WBITS:

inflateInit2(&stream, 16+MAX_WBITS);

Wenn Sie dies nicht tun, beschwert sich zlib über ein schlechtes Stream-Format. Standardmäßig erstellt zlib Streams mit einem zlib-Header und erkennt beim Aufblasen die verschiedenen gzip-Header nur, wenn Sie dies mitteilen. Obwohl dies ab Version 1.2.1 der zlib.hHeader-Datei dokumentiert ist , ist es nicht im zlib-Handbuch enthalten . Aus der Header-Datei:

windowBitskann für die optionale gzip-Dekodierung auch größer als 15 sein. Fügen Sie 32 hinzu, windowBitsum die Zlib- und GZIP-Dekodierung mit automatischer Header-Erkennung zu aktivieren, oder fügen Sie 16 hinzu, um nur das GZIP-Format zu dekodieren (das ZLIB-Format gibt a zurück Z_DATA_ERROR). Wenn ein gzip-Stream dekodiert wird, strm->adlerist ein crc32 anstelle eines adler32.


35
In Python:zlib.decompress(data, 15 + 32)
Roman Starkov

3
Danke, das war sehr frustrierend, bis ich diesen Beitrag gefunden habe.
Alex

Wow, das ist die Frage von 2009. Danke @ Greg Hewgill
YuAn Shaolin Maculelê Lai

Vielleicht können Sie einige Richtlinien für die iterative Dekomprimierung von gzip stream bereitstellen. Bei der One-Shot-GZIP-Dekomprimierung, bei der Ihr Ausgabestream und Ihre Größe fest und ausreichend sein sollten, um die gesamte dekomprimierte Ausgabe zu speichern. Dieser Wert hängt von der Wirksamkeit der gzip-Dekompression ab, die je nach Datenentropie variieren kann. Gibt es eine Möglichkeit, dem Ausgabepuffer bei Bedarf dynamisch mehr Speicherplatz zuzuweisen? Danke
Zohar81

103

Python

zlibBibliothek unterstützt :

Das Python- zlibModul unterstützt diese ebenfalls.

Fensterbits auswählen

Aber zlibkönnen alle diese Formate dekomprimieren:

  • deflateVerwenden Sie zum (De-) Komprimieren des Formatswbits = -zlib.MAX_WBITS
  • zlibVerwenden Sie zum (De-) Komprimieren des Formatswbits = zlib.MAX_WBITS
  • gzipVerwenden Sie zum (De-) Komprimieren des Formatswbits = zlib.MAX_WBITS | 16

Siehe Dokumentation unter http://www.zlib.net/manual.html#Advanced (Abschnitt inflateInit2)

Beispiele

Testdaten:

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

offensichtlicher Test für zlib:

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

Test für 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'

Test für 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'

Die Daten sind auch kompatibel mit gzipModul:

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

automatische Header-Erkennung (zlib oder gzip)

Durch Hinzufügen 32zu windowBitswird die Headererkennung ausgelöst

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

Verwendung gzipanstelle

Für gzipDaten mit gzip-Header können Sie das gzipModul direkt verwenden. aber denken Sie bitte daran , dass unter der Haube , gzipAnwendungen zlib.

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

3
Warum steht dieses Stück Gold nicht in den Dokumenten zu diesem Format?
Ramon Moraes

Bitte zögern Sie nicht, eine Pull-Anfrage / einen Patch gegen cpython mit einer dieser Antworten zu senden.
dnozay

Gute Antwort für Zeichenfolgen. Haben Sie eine Idee, wie Sie dies für einen Stream tun können, ohne die gesamte Datei in den Speicher einzulesen?
Josh J

Danke dir. Ich kann mein Dekomprimierungsproblem in meinem Quellcode mit Ihrer Antwort lösen.
Bethlee

Unglaublich, das ist ein Goldnugget. Aber ich kann nicht anders, als zu glauben, dass dies gleichbedeutend mit 'magischen Zahlen' ist. Wo in der Dokumentation wird dies erwähnt? Ich habe nachgesehen, muss aber wirklich nicht genau genug nachgesehen haben. Auch die Notation, der ich nicht vollständig folge. Was macht der | meine, ist das optional? und warum ist deflate negativ .. ist MAX_WBITS eine Konstante .. 🙁
m1nkeh

3

Die Struktur von zlib und gzip ist unterschiedlich. zlib verwendet RFC 1950 und gzip verwendet RFC 1952 , hat also unterschiedliche Header, aber der Rest hat die gleiche Struktur und folgt dem RFC 1951 .

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.