Cómo inflar un archivo zlib parcial

Tengo el primer 2 / 3rds contiguo de un archivo comprimido con la función deflate () de zlib. El último 1/3 se perdió en transmisión. El archivo original sin comprimir era de 600KB.

Deflate fue llamado varias veces por el transmisor mientras cortaba el archivo original en trozos de 2KB y pasaba Z_NO_FLUSH hasta el final del archivo cuando se pasaba Z_FINISH. El archivo comprimido completo resultante se transmitió, pero se perdió parcialmente como se describe.

¿Es posible recuperar parte del archivo original? Si es así, ¿alguna sugerencia sobre cómo?

Estoy usando tanto la implementación de C simple de ZLIB como la implementación de Python 2.7 de ZLIB.

Aunque no sé python, logré que esto funcionara:

#!/usr/bin/python import sys import zlib f = open(sys.argv[1], "rb") g = open(sys.argv[2], "wb") z = zlib.decompressobj() while True: buf = z.unconsumed_tail if buf == "": buf = f.read(8192) if buf == "": break got = z.decompress(buf) if got == "": break g.write(got) 

Eso debería extraer todo lo que está disponible de su archivo zlib parcial.

Actualización: Como lo señaló @Mark Adler ; El contenido parcial se puede descomprimir usando zlib.decompressobj :

 >>> decompressor = zlib.decompressobj() >>> decompressor.decompress(part) "let's compress some t" 

donde part se define a continuación.

— Antiguo comentario sigue:

Por defecto, zlib no maneja contenido parcial en Python.

Esto funciona:

 >>> compressed = "let's compress some text".encode('zip') >>> compressed 'x\x9c\xcbI-Q/VH\xce\xcf-(J-.V(\xce\xcfMU(I\xad(\x01\x00pX\t%' >>> compressed.decode('zip') "let's compress some text" 

No funciona si lo truncamos:

 >>> part = compressed[:3*len(compressed)/4] >>> part.decode('zip') Traceback (most recent call last): File "", line 1, in  File ".../lib/python2.7/encodings/zlib_codec.py", lin e 43, in zlib_decode output = zlib.decompress(input) error: Error -5 while decompressing data: incomplete or truncated stream 

Lo mismo si usamos zlib explícitamente:

 >>> import zlib >>> zlib.decompress(compressed) "let's compress some text" >>> zlib.decompress(part) Traceback (most recent call last): File "", line 1, in  error: Error -5 while decompressing data: incomplete or truncated stream 

Lo siguiente parece factible en teoría, pero necesita retoques con las rutinas zlib de bajo nivel para funcionar. En http://www.zlib.net/zlib_how.html encontramos un progtwig de ejemplo zpipe.c , y en su descripción línea por línea:

CHUNK es simplemente el tamaño del búfer para alimentar datos y extraer datos de las rutinas zlib. Los tamaños de búfer más grandes serían más eficientes, especialmente para inflar (). Si la memoria está disponible, se deben usar tamaños de búferes del orden de 128K o 256K bytes.

 #define CHUNK 16384 ... 

Aquí está mi sugerencia: establece el búfer muy pequeño; si es compatible, tal vez incluso a un solo byte. De esa manera, descomprimirás tanto como sea posible hasta el inevitable Z_BUF_ERROR . En ese momento, por lo general, se descartan los datos recostackdos (busque llamadas deflate_end prematuras que “limpian” detrás de su espalda) pero en su caso, simplemente puede transmitir a un archivo y cerrarlo cuando descubra que no puede continuar.

Los últimos bytes de salida pueden contener thrash si el símbolo “final” incorrecto se descodificó, o zlib puede abortar prematuramente, en lugar de emitir un símbolo parcial. Pero sabes que tus datos estarán incompletos de todos modos , así que eso no debería ser un problema.