2009-11-14 23 views
7

Así que aquí está el problema. Tengo el archivo sample.gz que tiene aproximadamente 60 KB de tamaño. Quiero descomprimir los primeros 2000 bytes de este archivo. Me estoy quedando sin un error de verificación de CRC, supongo porque el campo gzip CRC aparece al final del archivo y requiere descomprimir todo el archivo comprimido. ¿Hay alguna forma de evitar esto? No me importa el cheque CRC. Incluso si no puedo descomprimir debido a un CRC malo, eso está bien. ¿Hay alguna forma de evitar esto y descomprimir archivos .gz parciales?Descomprimir parte de un archivo .gz usando python

El código que tengo hasta ahora es

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 

El error encontrado es

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 

También hay alguna manera de utilizar el módulo zlib para hacer esto y pasar por alto las cabeceras gzip?

+0

Porque yo estoy interesado en la primera quizá 4k de los datos comprimidos. – user210126

Respuesta

11

Me parece que usted tiene que mirar en Python zlib biblioteca en lugar

El formato GZIP se basa en zlib, pero introduce el concepto de compresión de AA a nivel de archivo, junto con la comprobación de CRC, y esto parece ser lo que no quiere/Necesito en este momento.

Véase, por ejemplo, estos code snippets from Dough Hellman

Editar: el código en el sitio de Doubh Hellman sólo muestra cómo comprimir o descomprimir con zlib. Como se indicó anteriormente, GZIP es "zlib con un sobre", y deberá decodificar el envellope antes de llegar a los datos zlib-comprimidos per se. Aquí hay más información de hacerlo, en realidad no es tan complicado:

  • ver RFC 1952 para obtener detalles sobre el formato GZIP
  • Este formato comienza con una cabecera de 10 bytes, seguido de elementos opcionales, no comprimidos tales como la nombre de archivo o un comentario, seguido de los datos zlib-compressed, seguido por un CRC-32 (precisamente un CRC "Adler32").
  • Mediante el uso de Python's struct module, analizar la cabecera debe ser relativamente simple
  • La secuencia zlib (o sus primeros miles de bytes, ya que es lo que quiere hacer), entonces se puede descomprimir con el módulo zlib de pitón, como se muestra en la ejemplos arriba
  • Posibles problemas para manejar: si hay más de un archivo en el archivo GZip, y si el segundo archivo comienza dentro del bloque de unos pocos miles de bytes que deseamos descomprimir.

Lamentamos no proporcionar ni un procedimiento simple ni un fragmento listo para usar, sin embargo decodificar el archivo con la indicación anterior debe ser relativamente rápido y simple.

+0

@mjv ... Qué fragmento de código particular se aplica al ejemplo anterior. Revisé el enlace y leí Trabajando con Streams. En ninguna parte dice que está trabajando con streams gzip. Supongo que esto funciona con las transmisiones zlib (probadas con flujos zlib) – user210126

+0

@unknown: verifique mi edición; los fragmentos de código se refieren a la compresión/descompresión en/desde pure zlib. El formato GZip implica un análisis inicial de un encabezado pequeño sin comprimir, antes de encontrar su "carga útil" zlip que se puede descomprimir como se muestra. – mjv

8

No veo ninguna razón posible por la que desee descomprimir los primeros 2000 bytes comprimidos. Dependiendo de los datos, esto puede descomprimir a cualquier número de bytes de salida.

Seguramente que desea descomprimir el archivo, y se detendrá cuando haya descomprimido tanto del fichero como sea necesario, algo así como:

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

yo sepa, esto no hará que todo el archivo para ser leído . Solo leerá tanto como sea necesario para obtener los primeros 4000 bytes.

+0

f.read (2000) aquí leerá los primeros 2000 bytes de datos descomprimidos. Estoy interesado en los primeros 2000 bytes de datos comprimidos. – user210126

+0

¿Por qué? ¿Qué demonios es tu aplicación? – rjmunro

+0

:-) Estoy tratando de encontrar la cadena "xyz" en los primeros 4k de datos. Asumiendo que descomprimo 2K de datos comprimidos y aterrizo con 4K de datos descomprimidos, puedo buscar/grep en este 4k para la cadena. Todo el código de búsqueda ya está en su lugar. – user210126

2

También encuentro este problema cuando uso mi script python para leer archivos comprimidos generados por la herramienta gzip en Linux y los archivos originales se perdieron.

Al leer la implementación de gzip.py de Python, encontré que gzip.GzipFile tenía métodos similares de clase de archivo y módulo de python zip explotado para procesar datos de/compresión. Al mismo tiempo, el método _read_eof() también está presente para verificar el CRC de cada archivo.

embargo, en algunas situaciones, como el procesamiento de flujo o un archivo .gz sin CRC correcta (mi problema), una IOError ("comprobación CRC no") se incrementará en _read_eof(). Por lo tanto, trato de modificar el módulo gzip para desactivar la verificación CRC y finalmente este problema desapareció.

def _read_eof(self): 
    pass 

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

Sé que es una solución de fuerza bruta, pero se ahorrará mucho tiempo para volver a escribir usted mismo algunos métodos de bajo nivel usando el módulo de postal, al igual que de la lectura de la tirada de datos por la tirada de los archivos comprimidos y extrae los datos línea por línea, la mayoría de los cuales ha estado presente en el módulo gzip.

Jamin

13

El problema con el módulo gzip no es que no se puede descomprimir el archivo parcial, el error se produce sólo al final cuando se intenta verificar la suma de comprobación del contenido descomprimido. (La suma de comprobación original se almacena al final del archivo comprimido, por lo que la verificación nunca funcionará con un archivo parcial.)

La clave es engañar a gzip para que omita la verificación. El answer by caesar0301 hace esto modificando el código fuente de gzip, pero no es necesario ir tan lejos, el simple parche de mono servirá. Escribí este gestor de contexto para reemplazar temporalmente gzip.GzipFile._read_eof mientras que descomprimir el archivo parcial:

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 ejemplo de uso:

from cStringIO import StringIO 

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