2009-11-14 23 views
7

Quindi ecco il problema. Ho un file sample.gz che ha una dimensione di circa 60 KB. Voglio decomprimere i primi 2000 byte di questo file. Sto correndo in CRC controllo errore non riuscito, credo perché il campo CRC gzip appare alla fine del file, e richiede l'intero file gzippato per decomprimere. C'è un modo per aggirare questo? Non mi interessa il controllo CRC. Anche se non riesco a decomprimere a causa del cattivo CRC, va bene. C'è un modo per aggirare questo e decomprimere i file .gz parziali?Decompressione parte di un file .gz usando python

Il codice che ho finora è

import gzip 
import time 
import StringIO 

file = open('sample.gz', 'rb') 
mybuf = MyBuffer(file) 
mybuf = StringIO.StringIO(file.read(2000)) 
f = gzip.GzipFile(fileobj=mybuf) 
data = f.read() 
print data 

L'errore riscontrato è

File "gunzip.py", line 27, in ? 
    data = f.read() 
File "/usr/local/lib/python2.4/gzip.py", line 218, in read 
    self._read(readsize) 
File "/usr/local/lib/python2.4/gzip.py", line 273, in _read 
    self._read_eof() 
File "/usr/local/lib/python2.4/gzip.py", line 309, in _read_eof 
    raise IOError, "CRC check failed" 
IOError: CRC check failed 

Inoltre c'è un modo per utilizzare il modulo zlib per fare questo e ignorare le intestazioni gzip?

+0

Cuz Sono interessato nel primo forse 4k dei dati compressi. – user210126

risposta

11

mi sembra che avete bisogno di guardare in Python zlib biblioteca invece

Il formato GZIP si basa su zlib, ma introduce il concetto di compressione aa livello di file con controllo CRC, e questo sembra essere quello che non vuoi/bisogno al momento

Vedi per esempio questi code snippets from Dough Hellman

Edit: il codice sul sito di Doubh Hellman mostrano solo il modo per comprimere o decomprimere con zlib. Come indicato sopra, GZIP è "zlib con una busta" e dovrai decodificare l'envellope prima di ottenere i dati compressi con zlib di per sé. Ecco maggiori informazioni andare su di esso, non è poi così complicato:

  • vedere RFC 1952 per dettagli sul formato GZIP
  • Questo formato inizia con un'intestazione di 10 byte, seguito da elementi opzionali, non compressi come il nome del file o un commento, seguito dai dati compressi con zlib, seguito da un CRC-32 (precisamente un CRC "Adler32").
  • Utilizzando Python's struct module, parsing l'intestazione dovrebbe essere relativamente semplice
  • La sequenza zlib (o le prime poche migliaia di byte, dato che questo è ciò che si vuole fare) possono poi essere decompressi con il modulo zlib di pitone, come mostrato nella esempi sopra
  • Possibili problemi da gestire: se ci sono più file nell'archivio GZip e se il secondo file inizia nel blocco di poche migliaia di byte, desideriamo effettuare la decompressione.

Mi dispiace non fornire né una semplice procedura né uno snippet pronto per l'uso, tuttavia la decodifica del file con l'indicazione sopra dovrebbe essere relativamente rapida e semplice.

+0

@mjv ... Quale snippet di codice particolare si applica all'esempio sopra. Ho passato il link e ho letto Working with Stream. Da nessuna parte afferma che sta funzionando con i flussi gzip. Presumo che questo funzioni con i flussi zlib (sono stati testati con i flussi zlib) – user210126

+0

@unknown: Controlla la mia modifica; i frammenti di codice si riferiscono alla compressione/decompressione da/a zlib puro. Il formato GZip implica il pugno che analizza una piccola intestazione non compressa, prima di trovare il suo "payload" zlip che può essere decompresso come mostrato. – mjv

8

Non riesco a vedere alcun motivo possibile per cui si desidera decomprimere i primi 2000 byte compressi. A seconda dei dati, questo può decomprimere a un numero qualsiasi di byte di output.

Sicuramente si desidera decomprimere il file, e fermarsi quando si è decompresso il maggior numero di file di cui hai bisogno, qualcosa come:

f = gzip.GzipFile(fileobj=open('postcode-code.tar.gz', 'rb')) 
data = f.read(4000) 
print data 

per quanto ne so, questo non causerà l'intero file da leggere . Leggerà solo quanto è necessario per ottenere i primi 4000 byte.

+0

f.read (2000) qui leggerà i primi 2000 byte di dati decompressi. Sono interessato ai primi 2000 byte di dati compressi. – user210126

+0

Perché? Che diavolo è la tua applicazione? – rjmunro

+0

:-) Sto cercando di trovare la stringa "xyz" nel primo 4k di dati. Supponendo che io decomprima 2K di dati gzip e terra con 4K di dati decompressi, posso cercare/grep in questo 4k per la stringa. Tutto il codice di ricerca è già presente. – user210126

2

Ho riscontrato questo problema anche quando uso il mio script python per leggere i file compressi generati dallo strumento gzip su Linux e i file originali sono andati persi.

Leggendo l'implementazione di gzip.py di Python, ho trovato che gzip.GzipFile aveva metodi simili di classe File e il modulo zip Python utilizzato per elaborare i dati di/compressione. Allo stesso tempo, è presente anche il metodo _read_eof() per controllare il CRC di ogni file.

Ma in alcune situazioni, come l'elaborazione di file Stream o .gz senza CRC corretto (il mio problema), un errore IOError ("controllo CRC non riuscito") verrà sollevato da _read_eof(). Pertanto, provo a modificare il modulo gzip per disabilitare il controllo CRC e finalmente questo problema è scomparso.

def _read_eof(self): 
    pass 

https://github.com/caesar0301/PcapEx/blob/master/live-scripts/gzip_mod.py

Lo so che è una soluzione di forza bruta, ma risparmiare molto tempo per riscrivere se stessi alcuni metodi a basso livello utilizzando il modulo di cerniera, come di leggere chuck dati di Chuck dai file zip e estrarre i dati riga per riga, la maggior parte dei quali è stata presente nel modulo gzip.

Jamin

13

Il problema con il modulo gzip non è che non può decomprimere il file parziale, l'errore si verifica solo alla fine quando si tenta di verificare il checksum del contenuto non compresso. (Il checksum originale è archiviato alla fine del file compresso, quindi la verifica non funzionerà mai, mai con un file parziale.)

La chiave è ingannare gzip nel saltare la verifica. Lo answer by caesar0301 esegue questa operazione modificando il codice sorgente di gzip, ma non è necessario andare così lontano, le semplici patch di scimmia lo faranno. Ho scritto questo manager contesto per sostituire temporaneamente gzip.GzipFile._read_eof mentre io decomprimere il file parziale:

import contextlib 

@contextlib.contextmanager 
def patch_gzip_for_partial(): 
    """ 
    Context manager that replaces gzip.GzipFile._read_eof with a no-op. 

    This is useful when decompressing partial files, something that won't 
    work if GzipFile does it's checksum comparison. 

    """ 
    _read_eof = gzip.GzipFile._read_eof 
    gzip.GzipFile._read_eof = lambda *args, **kwargs: None 
    yield 
    gzip.GzipFile._read_eof = _read_eof 

Un esempio d'uso:

from cStringIO import StringIO 

with patch_gzip_for_partial(): 
    decompressed = gzip.GzipFile(StringIO(compressed)).read()