web-dev-qa-db-fra.com

Comment puis-je décompresser un flux gzip avec zlib?

Les fichiers au format Gzip (créés avec le programme gzip par exemple) utilisent l'algorithme de compression "deflate", qui est le même que celui utilisé par zlib . Cependant, lorsque vous utilisez zlib pour gonfler un fichier compressé gzip, la bibliothèque renvoie un Z_DATA_ERROR.

Comment utiliser zlib pour décompresser un fichier gzip?

102
Greg Hewgill

Pour décompresser un fichier au format gzip avec zlib, appelez inflateInit2 avec le paramètre windowBits comme 16+MAX_WBITS, comme ça:

inflateInit2(&stream, 16+MAX_WBITS);

Si vous ne le faites pas, zlib se plaindra d'un format de flux incorrect. Par défaut, zlib crée des flux avec un en-tête zlib, et sur inflate ne reconnaît pas les différents en-têtes gzip sauf si vous le spécifiez. Bien que cela soit documenté à partir de la version 1.2.1 de la zlib.h fichier d’en-tête, ce n’est pas dans le manuel de zlib . À partir du fichier d'en-tête:

windowBits peut également être supérieur à 15 pour le décodage optionnel gzip. Ajoutez 32 à windowBits pour activer le décodage zlib et gzip avec la détection automatique de l’en-tête, ou ajoutez 16 pour ne décoder que le format gzip (le format zlib renvoie un Z_DATA_ERROR). Si un flux gzip est en cours de décodage, strm->adler est un crc32 au lieu d'un adler32.

110
Greg Hewgill

python

zlib bibliothèques supportées :

Le module python zlib les supportera également.

choisir windowBits

Mais zlib peut décompresser tous ces formats:

  • pour (dé-) compresser le format deflate, utilisez wbits = -zlib.MAX_WBITS
  • pour (dé-) compresser le format zlib, utilisez wbits = zlib.MAX_WBITS
  • pour (dé-) compresser le format gzip, utilisez wbits = zlib.MAX_WBITS | 16

Voir la documentation dans http://www.zlib.net/manual.html#Advanced (section inflateInit2)

exemples

données de test:

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

test évident pour zlib:

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

test pour 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 pour 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'

les données sont également compatibles avec le module gzip:

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

détection automatique d'en-tête (zlib ou gzip)

ajouter 32 to windowBits déclenchera la détection d'en-tête

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

en utilisant gzip à la place

Pour les données gzip avec en-tête gzip, vous pouvez utiliser directement le module gzip; mais rappelez-vous que sous le capot , gzip utilise zlib.

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

La structure de zlib et de gzip est différente. zlib utilise RFC 195 et gzip utilise RFC 1952 , ont donc des en-têtes différents, mais le reste a la même structure et suit le RFC 1951 .

2
josep fon