¿Cómo puedo descomprimir una secuencia gzip con zlib?

108

Los archivos en formato Gzip (creados con el gzipprograma, por ejemplo) utilizan el algoritmo de compresión "desinflar", que es el mismo algoritmo de compresión que utiliza zlib . Sin embargo, cuando se usa zlib para inflar un archivo comprimido gzip, la biblioteca devuelve un Z_DATA_ERROR.

¿Cómo puedo usar zlib para descomprimir un archivo gzip?

Greg Hewgill
fuente

Respuestas:

118

Para descomprimir un archivo de formato gzip con zlib, llame inflateInit2con el windowBitsparámetro como 16+MAX_WBITS, así:

inflateInit2(&stream, 16+MAX_WBITS);

Si no lo hace, zlib se quejará de un formato de transmisión incorrecto. De forma predeterminada, zlib crea flujos con un encabezado zlib, y en inflate no reconoce el encabezado gzip diferente a menos que usted lo indique. Aunque esto está documentado a partir de la versión 1.2.1 del zlib.harchivo de encabezado, no está en el manual de zlib . Desde el archivo de encabezado:

windowBitstambién puede ser superior a 15 para la decodificación gzip opcional. Agregue 32 a windowBitspara habilitar la decodificación zlib y gzip con detección automática de encabezados, o agregue 16 para decodificar solo el formato gzip (el formato zlib devolverá a Z_DATA_ERROR). Si se está decodificando un flujo gzip, strm->adleres un crc32 en lugar de un adler32.

Greg Hewgill
fuente
35
En pitón:zlib.decompress(data, 15 + 32)
Roman Starkov
3
Gracias, esto fue muy frustrante hasta que encontré esta publicación.
Alex
Vaya, esta es la pregunta de 2009. Gracias @Greg Hewgill
YuAn Shaolin Maculelê Lai
Quizás pueda proporcionar algunas pautas para la descompresión iterativa del flujo gzip. En una descompresión gzip de una sola vez, donde el flujo de salida y el tamaño deben ser fijos y suficientes para almacenar toda la salida descomprimida. Este valor depende de la eficacia de la descompresión de gzip que puede variar según la entropía de los datos. ¿Hay alguna forma de asignar dinámicamente más espacio al búfer de salida cuando sea necesario? Gracias
Zohar81
104

pitón

zlibsoportes de biblioteca :

El zlibmódulo de Python también los admitirá.

elegir windowBits

Pero zlibpuede descomprimir todos esos formatos:

  • para (des) comprimir deflateformato, usewbits = -zlib.MAX_WBITS
  • para (des) comprimir zlibformato, usewbits = zlib.MAX_WBITS
  • para (des) comprimir gzipformato, usewbits = zlib.MAX_WBITS | 16

Ver documentación en http://www.zlib.net/manual.html#Advanced (sección inflateInit2)

ejemplos

datos de prueba:

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

prueba obvia para zlib:

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

prueba para 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'

prueba para 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'

los datos también son compatibles con el gzipmódulo:

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

detección automática de encabezados (zlib o gzip)

agregar 32a windowBitsactivará la detección de encabezado

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

utilizando gzip lugar

Para gzipdatos con encabezado gzip, puede usar el gzipmódulo directamente; pero recuerde que debajo del capó , gzipusa zlib.

fh = gzip.open('abc.gz', 'rb')
cdata = fh.read()
fh.close()
dnozay
fuente
3
¿Por qué esta pieza de oro no está en los documentos en este formato exactamente?
Ramon Moraes
no dude en enviar una solicitud de extracción / parche contra cpython utilizando cualquiera de esta respuesta.
dnozay
gran respuesta para cadenas, ¿alguna idea de cómo hacer esto para una secuencia sin leer todo el archivo en la memoria?
Josh J
Gracias. Puedo resolver mi problema de descompresión en mi código fuente con tu respuesta.
Bethlee
Increíble, esta es una pepita de oro ... sin embargo, no puedo evitar sentir que son equivalentes a 'números mágicos'. ¿En qué parte de la documentación se menciona esto? miré, pero en realidad no debí haberlo comprobado lo suficiente ... también, la notación que no sigo completamente. ¿Qué significa el | es decir, ¿eso es opcional? y por qué desinflar es negativo ... es MAX_WBITS una constante ... 🙁
m1nkeh
3

La estructura de zlib y gzip es diferente. zlib usa RFC 1950 y gzip usa RFC 1952 , por lo que tiene diferentes encabezados pero el resto tiene la misma estructura y sigue el RFC 1951 .

josep fon
fuente