2009-11-14 4 views
7

Итак, вот в чем проблема. У меня есть пример.gz-файла размером примерно 60 КБ. Я хочу распаковать первые 2000 байтов этого файла. Я столкнулся с ошибкой проверки CRC, я думаю, потому что в конце файла появляется поле CRC gzip, и для его распаковки требуется весь gzipped-файл. Есть ли способ обойти это? Меня не интересует проверка CRC. Даже если я не могу распаковать из-за плохого CRC, это нормально. Есть ли способ обойти это и распаковать частичные файлы .gz?Распаковка части файла .gz с использованием python

код у меня до сих пор

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 

ошибка встречается в

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 

Кроме того, есть ли способ использовать модуль ZLIB, чтобы сделать это, и игнорировать заголовки GZIP?

+0

Cuz Я заинтересован в первом возможно 4k сжатых данных. – user210126

ответ

11

Я, кажется, что вы должны смотреть в Python zlib библиотеку вместо

Формат GZIP зависит от Zlib, но вводит понятие сжатия аа на уровне файлов, а также CRC проверки, и это, кажется, что вы не хотите/нужно в данный момент.

Смотрите, например эти code snippets from Dough Hellman

Редактировать: код на сайте Doubh Хеллман только показать, как сжать или распаковать с Zlib. Как указано выше, GZIP является «zlib с конвертом», и вам нужно будет декодировать envellope, прежде чем получать данные с сжатым zlib per se. Вот больше информации, чтобы идти об этом, это действительно не так уж сложно:

  • см RFC 1952 подробности о формате GZIP
  • Этот формат начинается с заголовка 10 байт, а затем факультативных, не являющихся сжатых элементов, таких как имя файла или комментарий, за которым следуют сжатые zlib данные, за которыми следует CRC-32 (как правило, CRC Adler32).
  • С помощью Python's struct module, разбора заголовка должна быть относительно простой
  • Последовательность Zlib (или его первые несколько тысяч байт, так это то, что вы хотите сделать), то может быть распакованы с модулем ZLIB питона, как показано в примеры выше
  • Возможные проблемы с обработкой: если в архиве GZip имеется более одного файла, и если второй файл начинается с блока в несколько тысяч байт, мы хотим распаковать его.

Извините, что не предоставил ни простую процедуру, ни готовый к использованию фрагмент, однако декодирование файла с указанием выше должно быть относительно быстрым и простым.

+0

@mjv ... Какой конкретный фрагмент кода относится к приведенному выше примеру. Я прошел через ссылку и прочитал «Работа с потоками». Нигде не говорится, что он работает с потоками gzip. Я предполагаю, что это работает с потоками zlib (протестированы с потоками zlib) – user210126

+0

@unknown: проверьте мое редактирование; фрагменты кода относятся к сжатию/распаковке в/из чистого zlib. Формат GZip подразумевает, что кулак разбирает небольшой, несжатый заголовок, прежде чем найти свою «полезную нагрузку» zlip, которая может быть распакована, как показано. – mjv

8

Я не вижу никакой возможной причины, по которой вы захотите распаковать первые сжатые байты 2000 года. В зависимости от данных это может распаковываться на любое количество выходных байтов.

Конечно, вы хотите, чтобы разархивировать файл, и останавливается, когда вы распакованы, как большая часть файла, как вам нужно, что-то вроде:

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

AFAIK, это не вызовет весь файл для чтения , Он будет читать столько, сколько необходимо, чтобы получить первые 4000 байт.

+0

f.read (2000) здесь прочитает первые 2000 байт данных с декомпрессией. Меня интересуют первые 2000 байт сжатых данных. – user210126

+0

Почему? Каково ваше заявление? – rjmunro

+0

:-) Я пытаюсь найти строку «xyz» в первых 4k данных. Предполагая, что я распакую 2K данных gzipped и приземлюсь с 4K декомпрессированных данных, я могу искать/grep в этом 4k для строки. Весь код поиска уже установлен. – user210126

2

Я также сталкиваюсь с этой проблемой, когда я использую свой скрипт python для чтения сжатых файлов, сгенерированных инструментом gzip под Linux, и исходные файлы были потеряны.

Прочитав реализацию gzip.py Python, я обнаружил, что gzip.GzipFile имеет аналогичные методы класса File и эксплуатируемый zip-модуль python для обработки данных/сжатия. В то же время метод _read_eof() также присутствует для проверки CRC каждого файла.

Но в некоторых ситуациях, таких как обработка Stream или .gz-файла без правильного CRC (моя проблема), IOError («Ошибка CRC не удался») будет поднят _read_eof(). Поэтому я пытаюсь изменить модуль gzip, чтобы отключить проверку CRC, и, наконец, эта проблема исчезла.

def _read_eof(self): 
    pass 

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

Я знаю, что это перебор решение, но сэкономить много времени, чтобы переписать себе некоторые методы низкого уровня с помощью модуля зипа, как из чтения патрона данных по патроном из сжатых файлов и извлекать данные по строкам, большинство из которых присутствовало в модуле gzip.

Jamin

13

Проблема с модулем GZIP не то, что он не может распаковать файл частично, ошибка происходит только в конце, когда он пытается проверить контрольную сумму распакованного контента. (Исходная контрольная сумма хранится в конце сжатого файла, поэтому проверка никогда не будет работать с частичным файлом.)

Ключом является трюк gzip в пропуске проверки. answer by caesar0301 делает это, изменяя исходный код gzip, но не обязательно заходить так далеко, простое исправление обезьян будет делать. Я написал этот контекст менеджер временно заменить gzip.GzipFile._read_eof в то время как я распаковывать частичный файл:

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 

Пример использование:

from cStringIO import StringIO 

with patch_gzip_for_partial(): 
    decompressed = gzip.GzipFile(StringIO(compressed)).read() 
Смежные вопросы