2009-08-22 15 views
7

Bien, así que tengo algunas secuencias de datos comprimidas por la función python (2.6) zlib.compress(). Cuando trato de descomprimirlos, algunos de ellos no se descomprimen (zlib error -5, que parece ser un "error de búfer", ni idea de qué hacer con eso). Al principio, pensé que había terminado, pero me di cuenta de que todos los que no podía descomprimir comenzaban con 0x78DA (los de trabajo eran 0x789C), y miraba a mi alrededor y parecía ser un tipo diferente de compresión zlib: el el número mágico cambia según la compresión utilizada. ¿Qué puedo usar para descomprimir los archivos? ¿Tengo una manguera?descompresión zlib en python

+0

Especifique la versión de la biblioteca zlib contra la que compiló su intérprete de Python. –

+0

nos ayudaría mucho si pudiéramos ver el código que usaste para crear la transmisión. ¿Es posible que la versión con 0x78DA se haya escrito en el disco con un error, tal vez relacionado con la codificación? – Nelson

Respuesta

26

Según RFC 1950, la diferencia entre el 0x789C "OK" y el "malo" 0x78DA está en el campo de bits FLEVEL:

FLEVEL (Compression level) 
    These flags are available for use by specific compression 
    methods. The "deflate" method (CM = 8) sets these flags as 
    follows: 

     0 - compressor used fastest algorithm 
     1 - compressor used fast algorithm 
     2 - compressor used default algorithm 
     3 - compressor used maximum compression, slowest algorithm 

    The information in FLEVEL is not needed for decompression; it 
    is there to indicate if recompression might be worthwhile. 

"OK" utiliza 2, "malo" utiliza 3. Así esa diferencia en sí misma no es un problema.

Para obtener más información, considere proporcionar la siguiente información para cada uno de compresión e (intento) descompresión: qué plataforma, qué versión de Python, qué versión de la biblioteca zlib, cuál fue el código real utilizado para llamar al módulo zlib. También proporcione el rastreo completo y el mensaje de error de los intentos fallidos de descompresión. ¿Has intentado descomprimir los archivos con errores con cualquier otro software zlib-reading? ¿Con qué resultados? Por favor, aclare con qué tiene que trabajar: ¿Tengo "manguera"? ¿Quiere decir que no tiene acceso a los datos originales? ¿Cómo pasó de un flujo a un archivo? ¿Qué garantía tiene de que los datos no se dañaron en la transmisión?

ACTUALIZACIÓN Algunas observaciones sobre la base de las aclaraciones parciales publicados en su auto-respuesta:

está utilizando Windows. Windows distingue entre modo binario y modo de texto al leer y escribir archivos. Al leer en modo texto, Python 2.x cambia '\ r \ n' a '\ n' y cambia '\ n' a '\ r \ n' al escribir. Esta no es una buena idea cuando se trata de datos que no son de texto. Peor aún, cuando lee en modo texto, '\ x1a' aka Ctrl-Z se trata como final de archivo.

para comprimir un archivo:

# imports and other superstructure left as a exercise 
str_object1 = open('my_log_file', 'rb').read() 
str_object2 = zlib.compress(str_object1, 9) 
f = open('compressed_file', 'wb') 
f.write(str_object2) 
f.close() 

para descomprimir un archivo:

str_object1 = open('compressed_file', 'rb').read() 
str_object2 = zlib.decompress(str_object1) 
f = open('my_recovered_log_file', 'wb') 
f.write(str_object2) 
f.close() 

Aparte: Es mejor usar el módulo gzip que le ahorra tener que pensar en nasssties como modo de texto, en el costo de unos pocos bytes para la información adicional del encabezado.

Si ha estado usando 'rb' y 'wb' en su código de compresión, pero no en su código de descompresión [¿no es probable?], No necesita una manguera, solo necesita pulir el código de descompresión anterior y buscarlo .

Observe cuidadosamente el uso de "may", "should", etc. en las siguientes ideas no probadas.

Si no ha estado utilizando 'rb' y 'wb' en su código de compresión, la probabilidad de que se haya lavado una manguera es bastante alta.

Si hubo alguna instancia de '\ x1a' en su archivo original, se pierde cualquier dato después de la primera, pero en ese caso no debería fallar en la descompresión (IOW este escenario no coincide con sus síntomas)

Si Zlib generó una Ctrl-Z, esto debería provocar un EOF precoz al intentar la descompresión, lo que por supuesto debería causar una excepción.En este caso, puede invertir el proceso detenidamente al leer el archivo comprimido en modo binario y luego sustituir '\ r \ n' con '\ n' [es decir simular el modo de texto sin Ctrl-Z -> truco EOF]. Descomprime el resultado. Editar Escriba el resultado en modo TEXTO. Fin de edición

ACTUALIZACIÓN 2 puedo reproducir sus síntomas - con cualquier nivel del 1 al 9 - con el siguiente script:

import zlib, sys 
fn = sys.argv[1] 
level = int(sys.argv[2]) 
s1 = open(fn).read() # TEXT mode 
s2 = zlib.compress(s1, level) 
f = open(fn + '-ct', 'w') # TEXT mode 
f.write(s2) 
f.close() 
# try to decompress in text mode 
s1 = open(fn + '-ct').read() # TEXT mode 
s2 = zlib.decompress(s1) # error -5 
f = open(fn + '-dtt', 'w') 
f.write(s2) 
f.close() 

Nota: se necesita un uso un texto razonablemente grande archivo (utilicé un archivo fuente de 80kb) para asegurar que el resultado de la descompresión contenga un '\ x1a'.

puedo recuperar con este script:

import zlib, sys 
fn = sys.argv[1] 
# (1) reverse the text-mode write 
# can't use text-mode read as it will stop at Ctrl-Z 
s1 = open(fn, 'rb').read() # BINARY mode 
s1 = s1.replace('\r\n', '\n') 
# (2) reverse the compression 
s2 = zlib.decompress(s1) 
# (3) reverse the text mode read 
f = open(fn + '-fixed', 'w') # TEXT mode 
f.write(s2) 
f.close() 

NOTA: Si hay un '\ X1A' aka Ctrl-Z byte en el archivo original y el archivo se lee en modo texto, ese byte y todos los siguientes bytes NO se incluirán en el archivo comprimido y, por lo tanto, NO se pueden recuperar. Para un archivo de texto (por ejemplo, código fuente), esto no es una pérdida en absoluto. Para un archivo binario, lo más probable es que sea una manguera.

Actualización 3 [siguiente revelación tardía que hay una capa de cifrado/descifrado involucrados en el problema]:

El "error -5" mensaje indica que los datos que usted está tratando de descomprimir ha sido mutilado ya que estaba comprimido Si no es causado por el uso del modo de texto en los archivos, la sospecha obviamente (?) Recae en sus envoltorios de desencriptación y encriptación. Si desea ayuda, debe divulgar la fuente de esos envoltorios. De hecho, lo que debes intentar es (como yo lo hice) armar un pequeño script que reproduzca el problema en más de un archivo de entrada. En segundo lugar (como lo hice) ver si puede revertir el proceso bajo qué condiciones. Si desea ayuda con la segunda etapa, debe divulgar el script de reproducción del problema.

+2

+1 Respuesta muy completa. Estoy teniendo el mismo problema, aunque el búfer no se está leyendo desde un archivo, por lo que el modo binario no es un problema. Aun así, esta respuesta fue de gran ayuda para comprender el significado del error. – DNS

0

Bien, lo siento, no estaba lo suficientemente claro. Esto es win32, python 2.6.2. Me temo que no puedo encontrar el archivo zlib, pero es lo que está incluido en la versión binaria de win32. Y no tengo acceso a los datos originales. He estado comprimiendo mis archivos de registro y me gustaría recuperarlos. En cuanto a otro software, intenté 7zip, pero por supuesto falló, porque es zlib, no gzip (no pude usar ningún software para descomprimir las secuencias zlib directamente). No puedo dar una copia del rastreo ahora, pero fue (rastreado a zlib.decompress (data)) zlib.error: Error: -3. Además, para ser claros, estos son archivos estáticos, no transmisiones, ya que lo hice sonar antes (por lo que no hay errores de transmisión). Y me temo que nuevamente no tengo el código, pero sé que utilicé zlib.compress (data, 9) (es decir, en el nivel de compresión más alto, aunque, curiosamente, parece que no toda la salida de zlib es 78da como es de esperar ya que lo puse en el nivel más alto) y simplemente zlib.decompress().

+2

POR FAVOR edite su pregunta para incorporar estas aclaraciones. Algunos puntos que aún necesitan aclaración: (1) la pregunta dice el error -FIVE, pseudo-respuesta dice -THREE (2) ¿Por qué no puede dar una "copia de carbón" de la del traceback ahora? ¿Has eliminado los archivos comprimidos también? (3) intente recordar qué hizo su código de compresión desaparecido con el objeto str devuelto por zlib.compress() (4) intente recordar cómo su código de descompresión desaparecido obtuvo un objeto str para alimentar a zlib.decompress() –

0

Bien, perdón por mi última publicación, no tenía todo. Y no puedo editar mi publicación porque no utilicé OpenID.De todas formas, aquí está algunos datos:

1) Descompresión de rastreo: Código

Traceback (most recent call last): 
    File "<my file>", line 5, in <module> 
    zlib.decompress(data) 
zlib.error: Error -5 while decompressing data 

2) Compresión: Código

#here you can assume the data is the data to be compressed/stored 
data = encrypt(zlib.compress(data,9)) #a short wrapper around PyCrypto AES encryption 
f = open("somefile", 'wb') 
f.write(data) 
f.close() 

3) Descompresión:

f = open("somefile", 'rb') 
data = f.read() 
f.close() 

zlib.decompress(decrypt(data)) #this yeilds the error in (1) 
+0

Ver mi actualización de mi respuesta. –

3

que estaba buscando

python -c 'import sys,zlib;sys.stdout.write(zlib.decompress(sys.stdin.read()))' 

lo escribí yo mismo; basado en las respuestas de zlib decompression in python