Распаковка части файла .gz с помощью python

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

Код, который у меня есть до сих пор,

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?


person user210126    schedule 14.11.2009    source источник
comment
Потому что меня интересуют первые, может быть, 4 КБ сжатых данных.   -  person user210126    schedule 14.11.2009


Ответы (4)


Мне кажется, вам нужно заглянуть в библиотеку Python zlib вместо

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

См., например, эти фрагменты кода от Dough Hellman

Изменить: код на сайте Дауба Хеллмана показывает только, как сжимать или распаковывать с помощью zlib. Как указано выше, GZIP — это «zlib с конвертом», и вам нужно будет декодировать конверт перед тем, как получить сжатые zlib данные как таковые. Вот еще информация, чтобы пойти об этом, это действительно не так уж сложно:

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

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

person mjv    schedule 14.11.2009
comment
@mjv... Какой конкретный фрагмент кода относится к приведенному выше примеру. Я прошел по ссылке и прочитал Работа с потоками. Нигде не указано, что он работает с потоками gzip. Я предполагаю, что это работает с потоками zlib (проверено с потоками zlib) - person user210126; 14.11.2009
comment
@unknown: проверьте мое редактирование; фрагменты кода относятся к сжатию/распаковке в/из чистого zlib. Формат GZip подразумевает первоначальный анализ небольшого несжатого заголовка, прежде чем найти его полезные данные zlip, которые можно распаковать, как показано. - person mjv; 14.11.2009

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

Ключ в том, чтобы заставить gzip пропустить проверку. ответ от 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()
person jiffyclub    schedule 03.09.2013

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

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

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

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

person rjmunro    schedule 14.11.2009
comment
Здесь f.read(2000) будет читать первые 2000 байт распакованных данных. Меня интересуют первые 2000 байт сжатых данных. - person user210126; 14.11.2009
comment
Почему? Каково ваше приложение? - person rjmunro; 14.11.2009
comment
:-) Я пытаюсь найти строку xyz в первых 4k данных. Предполагая, что я распаковал 2 КБ данных, сжатых gzip, и получил 4 КБ распакованных данных, я могу выполнить поиск / grep в этих 4 КБ для строки. Весь поисковый код уже на месте.. - person user210126; 14.11.2009
comment
Предположим, что все, что я собираюсь получить, это первые 2 КБ сжатых данных из файла .gz размером 60 КБ. После этого ничего. Нада. Мне нужно найти мою строку в распакованной части этого 2k - person user210126; 14.11.2009
comment
Если вы хотите искать первые 4k несжатых данных, ищите первые 4k несжатых данных, как я делаю в своем ответе (возможно, измените 4000 на 4096). Не пытайтесь угадать, что 2k распакуется в 4k. Это не может быть. Он может распаковываться только до 2 КБ или может распаковываться до пары мегабайт. - person rjmunro; 28.05.2012
comment
Это потрясающе. Большое спасибо! Не нужно грязных хаков. - person Marco Roy; 08.11.2017

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

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

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

def _read_eof(self):
    pass

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

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

Джамин

person caesar0301    schedule 12.05.2013