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?

Greg Hewgill
quelle

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.

Greg Hewgill
quelle
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()
dnozay
quelle
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 .

josep fon
quelle