2009-08-22 13 views
7

Ok, quindi ho alcuni flussi di dati compressi dalla funzione zlib.compress() di python (2.6). Quando provo a decomprimerli, alcuni di loro non decomprimeranno (errore di zlib -5, che sembra essere un "errore di buffer", non ho idea di cosa fare di questo). All'inizio pensavo di aver finito, ma mi sono reso conto che tutti quelli che non potevo decomprimere iniziarono con 0x78DA (quelli funzionanti erano 0x789C), e mi sono guardato intorno e sembra essere un diverso tipo di compressione zlib - il il numero magico cambia a seconda della compressione utilizzata. Cosa posso usare per decomprimere i file? Sono stato ucciso?decompressione zlib in python

+0

Specificare la versione della libreria zlib su cui è stato compilato l'interprete Python. –

+0

sarebbe di grande aiuto se potessimo vedere il codice che hai usato per creare lo stream. È possibile che la versione con 0x78DA sia stata scritta sul disco con un bug, forse correlato alla codifica? – Nelson

risposta

26

Secondo RFC 1950, la differenza tra il 0x789C "OK" e il "cattivo" 0x78DA è nella FLEVEL campo bit:

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" usa 2, "cattivo" usa 3. Quindi, questa differenza in sé non è un problema.

Per ottenere ulteriori informazioni, si potrebbe considerare di fornire le seguenti informazioni per ciascuna compressione e (tentativo) di decompressione: quale piattaforma, quale versione di Python, quale versione della libreria zlib, quale era il codice effettivo utilizzato per chiamare il modulo zlib. Fornire inoltre il traceback completo e il messaggio di errore dai tentativi di decompressione non riusciti. Hai provato a decomprimere i file in errore con altri software di lettura zlib? Con quali risultati? Si prega di chiarire che cosa si deve lavorare: "Am I hosed?" significa che non hai accesso ai dati originali? Come è passato da un flusso ad un file? Che garanzia hai che i dati non siano stati stravolti nella trasmissione?

UPDATE Alcune osservazioni sulla base di chiarimenti parziali pubblicati nella vostra auto-risposta:

Si utilizza Windows. Windows distingue tra modalità binaria e modalità testo durante la lettura e la scrittura di file. Durante la lettura in modalità testo, Python 2.x cambia '\ r \ n' in '\ n' e cambia '\ n' in '\ r \ n' durante la scrittura. Questa non è una buona idea quando si tratta di dati non testuali. Peggio ancora, quando si legge in modalità testo, '\ x1a' alias Ctrl-Z viene trattato come end-of-file.

per comprimere un file:

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

Per decomprimere un file:

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

parte: meglio usare il modulo di gzip, che evita di dover pensare a nasssties come modalità testo, al costo di pochi byte per le informazioni di intestazione extra.

Se avete usato 'rb' e 'wb' nel codice di compressione, ma non nel codice di decompressione [improbabile?], Che non contengano errori, hai solo bisogno di rimpolpare il codice di decompressione sopra e andare per esso .

Nota attentamente l'uso di "può", "dovrebbe", ecc. Nelle seguenti idee non verificate .

Se non si stanno usando 'rb' e 'wb' nel proprio codice di compressione, la probabilità di avere un hosed da soli è piuttosto alta.

Se ci fossero casi di '\ X1A' nel file originale, tutti i dati dopo la prima di queste è perduto - ma in quel caso non dovrebbe fallire su di decompressione (IOW questo scenario non corrisponde i sintomi).

Se un Ctrl-Z è stato generato da zlib stesso, questo dovrebbe causare un EOF iniziale al tentativo di decompressione, che dovrebbe naturalmente causare un'eccezione.In questo caso potresti essere in grado di invertire cautamente il processo leggendo il file compresso in modalità binaria e quindi sostituire '\ r \ n' con '\ n' [vale a dire. simula la modalità testo senza Ctrl-Z -> EOF gimmick]. Decomprimere il risultato. Modifica Scrivi il risultato in modalità TESTO. Fine modifica

UPDATE 2 posso riprodurre i sintomi - con qualsiasi livello da 1 a 9 - con il seguente 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: avrete bisogno di un uso ragionevolmente testo di grandi dimensioni file (ho usato un file sorgente 80kb) per garantire che il risultato della decompressione conterrà un '\ x1a'.

posso recuperare con questo 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: Se c'è un '\ X1A' alias Ctrl-Z byte del file originale, e il file viene letto in modalità testo, che di byte e tutti i seguenti byte NON saranno inclusi nel file compresso, e quindi NON possono essere recuperati. Per un file di testo (ad esempio il codice sorgente), questa non è una perdita. Per un file binario, è molto probabile che tu sia un hosed.

Update 3 [segue in ritardo rivelazione che ci sia un livello di crittografia/decrittografia coinvolti nel problema]:

Il "Errore -5" messaggio indica che i dati che si sta tentando di decomprimere sia stato storpiato dal momento che è stato compresso. Se non è causato dall'uso della modalità testo sui file, il sospetto ovviamente (?) Ricade sulla decrittografia e sui wrapper di crittografia. Se vuoi aiuto, devi divulgare la fonte di quei wrapper. In effetti, ciò che dovresti provare a fare è (come ho fatto io) mettere insieme un piccolo script che riproduce il problema su più di un file di input. In secondo luogo (come ho fatto io) vedere se è possibile invertire il processo in quali condizioni. Se vuoi aiuto con il secondo stadio, devi divulgare lo script di riproduzione del problema.

+2

+1 Risposta molto accurata. Sto avendo lo stesso problema, anche se il buffer non viene letto da un file, quindi la modalità binaria non è un problema. Anche così, questa risposta è stata di grande aiuto per comprendere il significato dell'errore. – DNS

0

Ok, scusa, non ero abbastanza chiaro. Questo è Win32, Python 2.6.2. Temo di non riuscire a trovare il file zlib, ma è tutto incluso nella versione binaria win32. E non ho accesso ai dati originali: ho compresso i miei file di registro e mi piacerebbe riaverli indietro. Per quanto riguarda altri software, ho provato nettamente a 7zip, ma ovviamente non è riuscito, perché è zlib, non gzip (non potevo software per decomprimere direttamente i flussi zlib). Non posso dare una copia carbone del traceback ora, ma è stato (risalito a zlib.decompress (dati)) zlib.error: Errore: -3. Inoltre, per essere chiari, questi sono file statici, non flussi come ho fatto sembrare in precedenza (quindi nessun errore di trasmissione). E temo di nuovo che non ho il codice, ma so che ho usato zlib.compress (data, 9) (cioè al livello di compressione più alto - anche se, curiosamente, sembra che non tutto l'output di zlib sia 78da come ci si potrebbe aspettare dato che l'ho messo al livello più alto) e solo zlib.decompress().

+2

PER FAVORE, modifica la tua domanda per integrare questi chiarimenti. Alcuni punti che necessitano ancora di chiarimenti: (1) la domanda dice errore -FIVE, la pseudo-risposta dice -THREE (2) Perché non puoi dare una "copia carbone" del traceback adesso? Hai cancellato anche i file compressi ?? (3) prova a ricordare cosa ha fatto il tuo codice di compressione sparito con l'oggetto str restituito da zlib.compress() (4) prova a ricordare come il tuo codice decompressione sparito ha ottenuto un oggetto str da inviare a zlib.decompress() –

0

Ok scusa per il mio ultimo post, non avevo tutto. E non posso modificare il mio post perché non ho usato OpenID.In ogni modo, ecco alcuni dati:

1) decompressione traceback: codice

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

2) Compressione: Codice

#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) di decompressione:

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

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

Vedi il mio aggiornamento della mia risposta –

3

che cercavo

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

scritto da solo; in base alle risposte di zlib decompression in python