2013-12-16 35 views
6

Ho i primi 2/3 contigui di un file che è stato compresso con la funzione deflate() di zlib. L'ultimo 1/3 è stato perso nella trasmissione. Il file originale non compresso era 600 KB.Come gonfiare un file zlib parziale

Deflate è stato chiamato più volte dal trasmettitore mentre tagliava il file originale in blocchi di dimensioni di 2 KB e passava Z_NO_FLUSH fino alla fine del file quando veniva passato Z_FINISH. Il file compresso completo risultante è stato trasmesso, ma parzialmente perso come descritto.

È possibile ripristinare parte del file originale? Se sì, qualche suggerimento su come?

Sto usando sia l'implementazione C semplice di ZLIB, e/o l'implementazione Python 2.7 di ZLIB.

risposta

10

Anche se non so python, sono riuscito ad ottenere questo lavoro:

#!/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) 

Questo dovrebbe estrarre tutto ciò che è disponibile dal file zlib parziale.

+0

Grazie, sì utilizzando decompressobj() lavorato. Stavo semplicemente usando zlib.decompress() e stava dando un errore. Utilizzando dc_obj = zlib.decompressobj() e decomp_data_str = dc_obj.decompress (orig_data_str) hai risolto il problema. – JohnSantaFe

0

Il seguente sembra in teoria, ma è necessario armeggiare con routine zlib di basso livello per funzionare. In http://www.zlib.net/zlib_how.html troviamo un programma esempio zpipe.c, e nella sua riga per riga descrittiva:

blocco è semplicemente la dimensione del buffer di alimentazione dati da e tirando i dati dalla routine zlib. Dimensioni di buffer più grandi sarebbero più efficienti, specialmente per il gonfiaggio(). Se la memoria è disponibile, è necessario utilizzare dimensioni dei buffer dell'ordine di 128 K o 256 Kbyte.

#define CHUNK 16384 
... 

Ecco la mia proposta: Si imposta il buffer molto piccolo - se supportato, forse anche per un singolo byte. In questo modo, decomprimerai il più possibile fino all'inevitabile Z_BUF_ERROR. A quel punto, di solito si scarta i dati raccolti (cercare le chiamate deflate_end premature che "puliscono" dietro la schiena), ma nel tuo caso potresti semplicemente eseguire lo streaming su un file e chiuderlo quando non riesci a proseguire.

Gli ultimi pochi byte di output possono contenere thrash se il simbolo "finale" errato viene decodificato, o zlib può abortire prematuramente, piuttosto che emettere un simbolo parziale. Ma sai che i tuoi dati saranno incompleti in ogni caso, quindi non dovrebbe essere un problema.

2

Aggiornamento: come @Mark Adler pointed out; contenuto parziale può essere decompresso utilizzando zlib.decompressobj:

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

dove part è definito di seguito.

--- Vecchio commento segue:

Per impostazione predefinita zlib non gestisce contenuto parziale in Python.

Questo funziona:

>>> 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" 

Non funziona se si tronca:

>>> part = compressed[:3*len(compressed)/4] 
>>> part.decode('zip') 
Traceback (most recent call last): 
    File "<input>", line 1, in <module> 
    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 stesso se usiamo zlib esplicitamente:

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