2009-11-14 9 views
7

Donc, voici le problème. J'ai un fichier sample.gz d'environ 60 Ko. Je veux décompresser les 2000 premiers octets de ce fichier. Je suis en cours d'exécution dans la vérification CRC a échoué erreur, je suppose que parce que le champ CRC gzip apparaît à la fin du fichier, et il nécessite le fichier gzip entier pour décompresser. Y a-t-il un moyen de contourner ceci? Je me fiche de la vérification du CRC. Même si je ne parviens pas à décompresser à cause d'un mauvais CRC, c'est OK. Est-il possible de contourner ce problème et de décompresser les fichiers .gz partiels?Décompresser une partie d'un fichier .gz en utilisant python

Le code que j'ai est jusqu'à présent

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'erreur rencontrée est

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 

Aussi est-il un moyen d'utiliser le module zlib pour le faire et ignorer les en-têtes de gzip?

+0

Cuz Je suis intéressé par la première 4k peut-être des données compressées. – user210126

Répondre

11

Je semble que vous devez regarder dans Python zlib bibliothèque au lieu

Le format GZIP repose sur zlib, mais introduit aa concept de compression au niveau des fichiers ainsi que le contrôle CRC, et cela semble être ce que vous ne voulez pas/besoin pour le moment.

Voir par exemple ces code snippets from Dough Hellman

Modifier: le code sur le site de Doubh Hellman montrent seulement comment compresser ou décompresser avec zlib. Comme indiqué ci-dessus, GZIP est "zlib avec une enveloppe", et vous devrez décoder l'envellope avant d'obtenir les données compressées par zlib en soi. Voici plus d'information à prendre, il est vraiment pas si compliqué que ça:

  • voir RFC 1952 pour plus de détails sur le format GZIP
  • Ce format commence par un en-tête de 10 octets, suivi d'option, des éléments non compressés tels que le un nom de fichier ou un commentaire, suivi des données compressées par zlib, lui-même suivi d'un CRC-32 (précisément un CRC "Adler32").
  • En utilisant Python's struct module, analyse l'en-tête devrait être relativement simple
  • La séquence zlib (ou ses premiers milliers d'octets, puisque c'est ce que vous voulez faire) peut ensuite être décompressé avec le module zlib de python, comme indiqué dans le exemples ci-dessus
  • Problèmes possibles à gérer: s'il y a plus d'un fichier dans l'archive GZip, et si le second fichier commence dans le bloc de quelques milliers d'octets, nous souhaitons décompresser.

Désolé de ne fournir ni une procédure simple ni un extrait prêt à l'emploi, mais décoder le fichier avec l'indication ci-dessus devrait être relativement rapide et simple.

+0

@mjv ... Quel extrait de code particulier s'applique à l'exemple ci-dessus. J'ai parcouru le lien et j'ai lu Travailler avec des flux. Il ne dit nulle part qu'il travaille avec des flux gzip. Je suppose que cela fonctionne avec les flux zlib (ont testé avec les flux zlib) – user210126

+0

@unknown: Vérifiez ma modification; les extraits de code se rapportent à la compression/décompression de/à zlib pur. Le format GZip implique une première analyse d'un petit en-tête non compressé avant de trouver sa "charge utile" zlip qui peut être décompressée comme indiqué. – mjv

8

Je ne vois pas pourquoi vous voudriez décompresser les 2000 premiers octets compressés. Selon les données, cela peut décompresser à n'importe quel nombre d'octets de sortie.

Sûrement vous voulez décompresser le fichier, et arrêtez quand vous avez décompressé autant du fichier que vous avez besoin, quelque chose comme:

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

AFAIK, cela ne fera pas à lire tout le fichier . Il ne lira que ce qui est nécessaire pour obtenir les premiers 4000 octets.

+0

f.read (2000) lira ici les premiers 2000 octets de données décompressées. Je suis intéressé par les 2000 premiers octets de données compressées. – user210126

+0

Pourquoi? Que diable est votre application? – rjmunro

+0

:-) J'essaye de trouver la chaîne "xyz" dans le premier 4k de données. En supposant que je décompresse 2K de données gzipées et atterrisse avec 4K de données décompressées, je peux rechercher/grep dans ce 4k pour la chaîne. Tout le code de recherche est déjà en place. – user210126

2

Je rencontre également ce problème lorsque j'utilise mon script python pour lire les fichiers compressés générés par l'outil gzip sous Linux et les fichiers d'origine ont été perdus. En lisant l'implémentation de gzip.py de Python, j'ai trouvé que gzip.GzipFile avait des méthodes similaires à celles de la classe File et du module zip python exploité pour traiter les données de/compression. En même temps, la méthode _read_eof() est également présente pour vérifier le CRC de chaque fichier.

Mais dans certaines situations, comme le traitement d'un fichier Stream ou .gz sans CRC correct (mon problème), un IOError ("échec du contrôle CRC") sera déclenché par _read_eof(). Par conséquent, j'essaye de modifier le module de gzip pour désactiver le contrôle de CRC et finalement ce problème a disparu.

def _read_eof(self): 
    pass 

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

Je sais que c'est une solution de force brute, mais il économise beaucoup de temps pour vous-même réécrire certaines méthodes de bas niveau à l'aide du module zip, comme la lecture Mandrin de données par mandrin à partir des fichiers compressés et extraire les données ligne par ligne, dont la plupart ont été présentes dans le module gzip.

Jamin

13

Le problème avec le module gzip n'est pas qu'il ne peut pas décompresser le fichier partiel, l'erreur se produit uniquement à la fin quand il essaie de vérifier la somme de contrôle du contenu décompressé. (La somme de contrôle d'origine est stockée à la fin du fichier compressé afin que la vérification ne fonctionne jamais avec un fichier partiel.)

La clé consiste à tromper gzip en ignorant la vérification. Le answer by caesar0301 le fait en modifiant le code source de gzip, mais il n'est pas nécessaire d'aller aussi loin, le simple patch de singe suffira. J'ai écrit ce gestionnaire de contexte pour remplacer temporairement gzip.GzipFile._read_eof alors que je Décompressez le fichier partiel:

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 exemple d'utilisation:

from cStringIO import StringIO 

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