Распаковка zlib в Python

Итак, у меня есть потоки данных, сжатые функцией zlib.compress () python (2.6). Когда я пытаюсь их распаковать, некоторые из них не распаковываются (ошибка zlib -5, которая кажется «ошибкой буфера», не знаю, что с этим делать). Сначала я подумал, что все готово, но я понял, что все те, которые я не мог распаковать, начинались с 0x78DA (рабочие были 0x789C), и я огляделся и, похоже, это другой вид сжатия zlib - магическое число меняется в зависимости от используемого сжатия. Что я могу использовать для распаковки файлов? Я в шланге?


person Community    schedule 22.08.2009    source источник
comment
Укажите версию библиотеки zlib, с которой был скомпилирован ваш интерпретатор Python.   -  person Charles Duffy    schedule 22.08.2009
comment
было бы очень полезно, если бы мы могли видеть код, который вы использовали для создания потока. Возможно ли, что версия с 0x78DA была записана на диск с ошибкой, возможно, связанной с кодировкой?   -  person Nelson    schedule 23.08.2009


Ответы (4)


Согласно RFC 1950, разница между «OK» 0x789C и «плохим» 0x78DA находится в битовом поле FLEVEL:

  FLEVEL (Compression level)
     These flags are available for use by specific compression
     methods.  The "deflate" method (CM = 8) sets these flags as
     follows:

        0 - compressor used fastest algorithm
        1 - compressor used fast algorithm
        2 - compressor used default algorithm
        3 - compressor used maximum compression, slowest algorithm

     The information in FLEVEL is not needed for decompression; it
     is there to indicate if recompression might be worthwhile.

«ОК» использует 2, «плохое» - 3. Так что эта разница сама по себе не проблема.

Чтобы продвинуться дальше, вы можете подумать о предоставлении следующей информации для каждого из сжатия и (попытки) распаковки: какая платформа, какая версия Python, какая версия библиотеки zlib, какой фактический код использовался для вызова модуля zlib. Также предоставьте полную трассировку и сообщение об ошибке неудачных попыток декомпрессии. Вы пытались распаковать неисправные файлы с помощью какой-либо другой программы для чтения zlib? С какими результатами? Пожалуйста, поясните, с чем вам предстоит работать: "Меня обливают?" означает, что у вас нет доступа к исходным данным? Как оно попало из потока в файл? Какая у вас гарантия, что данные не были искажены при передаче?

ОБНОВЛЕНИЕ. Некоторые наблюдения основаны на частичных пояснениях, опубликованных в вашем самоответе:

Вы используете Windows. Windows различает двоичный режим и текстовый режим при чтении и записи файлов. При чтении в текстовом режиме Python 2.x меняет '\ r \ n' на '\ n' и меняет '\ n' на '\ r \ n' при записи. Это не лучшая идея при работе с нетекстовыми данными. Хуже того, при чтении в текстовом режиме '\ x1a' или Ctrl-Z обрабатывается как конец файла.

Чтобы сжать файл:

# imports and other superstructure left as a exercise
str_object1 = open('my_log_file', 'rb').read()
str_object2 = zlib.compress(str_object1, 9)
f = open('compressed_file', 'wb')
f.write(str_object2)
f.close()

Чтобы распаковать файл:

str_object1 = open('compressed_file', 'rb').read()
str_object2 = zlib.decompress(str_object1)
f = open('my_recovered_log_file', 'wb')
f.write(str_object2)
f.close()

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

Если вы использовали 'rb' и 'wb' в своем коде сжатия, но не использовали код декомпрессии [маловероятно?], Вы не заблудились, вам просто нужно конкретизировать приведенный выше код декомпрессии и действовать.

Внимательно обратите внимание на использование «может», «следует» и т. Д. В следующих непроверенных идеях.

Если вы не использовали «rb» и «wb» в своем коде сжатия, вероятность того, что вы залили себя, довольно высока.

Если в исходном файле были какие-либо экземпляры '\ x1a', любые данные после первого такового будут потеряны, но в этом случае он не должен завершиться сбоем при декомпрессии (IOW этот сценарий не соответствует вашим симптомам).

Если Ctrl-Z был сгенерирован самим zlib, это должно вызвать ранний EOF при попытке декомпрессии, что, конечно же, должно вызвать исключение. В этом случае вы можете осторожно отменить процесс, прочитав сжатый файл в двоичном режиме, а затем заменив '\ r \ n' на '\ n' [т.е. имитировать текстовый режим без уловки Ctrl-Z -> EOF]. Распаковать результат. Изменить. Выведите результат в текстовом режиме. Конец редактирования

ОБНОВЛЕНИЕ 2. Я могу воспроизвести ваши симптомы - с ЛЮБЫМ уровнем от 1 до 9 - с помощью следующего скрипта:

import zlib, sys
fn = sys.argv[1]
level = int(sys.argv[2])
s1 = open(fn).read() # TEXT mode
s2 = zlib.compress(s1, level)
f = open(fn + '-ct', 'w') # TEXT mode
f.write(s2)
f.close()
# try to decompress in text mode
s1 = open(fn + '-ct').read() # TEXT mode
s2 = zlib.decompress(s1) # error -5
f = open(fn + '-dtt', 'w')
f.write(s2)
f.close()

Примечание: вам понадобится достаточно большой текстовый файл (я использовал исходный файл размером 80 КБ), чтобы гарантировать, что результат распаковки будет содержать '\ x1a'.

Я могу восстановить с помощью этого скрипта:

import zlib, sys
fn = sys.argv[1]
# (1) reverse the text-mode write
# can't use text-mode read as it will stop at Ctrl-Z
s1 = open(fn, 'rb').read() # BINARY mode
s1 = s1.replace('\r\n', '\n')
# (2) reverse the compression
s2 = zlib.decompress(s1)
# (3) reverse the text mode read
f = open(fn + '-fixed', 'w') # TEXT mode
f.write(s2)
f.close()

ПРИМЕЧАНИЕ. Если в исходном файле есть байт '\ x1a', также известный как Ctrl-Z, и файл читается в текстовом режиме, этот байт и все последующие байты НЕ будут включены в сжатый файл и, следовательно, могут НЕ восстанавливаться. Для текстового файла (например, исходного кода) это вообще не потеря. В случае двоичного файла вы, скорее всего, попали в разряд.

Обновление 3 [после позднего обнаружения того, что проблема связана с уровнем шифрования / дешифрования]:

Сообщение «Ошибка -5» указывает на то, что данные, которые вы пытаетесь распаковать, были искажены с момента сжатия. Если это не вызвано использованием текстового режима для файлов, подозрение явно (?) Падает на ваши оболочки для дешифрования и шифрования. Если вам нужна помощь, вам нужно сообщить источник этих оболочек. Фактически, вы должны попытаться (как и я) собрать небольшой скрипт, который воспроизводит проблему более чем в одном входном файле. Во-вторых (как и я) посмотрите, можете ли вы повернуть процесс вспять при каких условиях. Если вам нужна помощь на втором этапе, вам нужно разгласить сценарий воспроизведения проблемы.

person John Machin    schedule 22.08.2009
comment
+1 Очень обстоятельный ответ. У меня та же проблема, хотя буфер не читается из файла, поэтому двоичный режим не является проблемой. Тем не менее, этот ответ очень помог понять смысл ошибки. - person DNS; 22.10.2009

Я искал

python -c 'import sys,zlib;sys.stdout.write(zlib.decompress(sys.stdin.read()))'

написал это сам; на основе ответов распаковки zlib в python

person 166_MMX    schedule 21.07.2017

Ладно, извини, я недостаточно ясно понял. Это win32, python 2.6.2. Боюсь, я не могу найти файл zlib, но это все, что включено в двоичную версию win32. И у меня нет доступа к исходным данным - я сжимал файлы журналов и хотел бы вернуть их. Что касается другого программного обеспечения, я наивно пробовал 7zip, но, конечно, он потерпел неудачу, потому что это zlib, а не gzip (я не мог напрямую распаковывать потоки zlib). Я не могу предоставить точную копию трассировки сейчас, но она была (прослежена до zlib.decompress (data)) zlib.error: Error: -3. Кроме того, для ясности, это статические файлы, а не потоки, как я говорил ранее (так что ошибок передачи нет). И я снова боюсь, что у меня нет кода, но я знаю, что использовал zlib.compress (data, 9) (то есть на самом высоком уровне сжатия - хотя, что интересно, кажется, что не весь вывод zlib имеет 78da, поскольку вы могли ожидать, так как я поставил его на высший уровень) и просто zlib.decompress ().

person Community    schedule 23.08.2009
comment
ПОЖАЛУЙСТА, отредактируйте свой вопрос, чтобы включить эти пояснения. Некоторые моменты, которые все еще нуждаются в пояснении: (1) вопрос говорит об ошибке -ПЯТЬ, псевдо-ответ говорит -ТРИ (2) Почему вы не можете предоставить точную копию трассировки сейчас? Вы также удалили сжатые файлы ?? (3) попробуйте вспомнить, что ваш исчезнувший код сжатия сделал с объектом str, возвращенным zlib.compress () (4) попробуйте вспомнить, как ваш исчезнувший код распаковки получил объект str для передачи в zlib.decompress () - person John Machin; 23.08.2009

Хорошо, извините за мой последний пост, у меня не было всего. И я не могу редактировать свой пост, потому что не использовал OpenID. В любом случае, вот некоторые данные:

1) Отслеживание декомпрессии:

Traceback (most recent call last):
  File "<my file>", line 5, in <module>
    zlib.decompress(data)
zlib.error: Error -5 while decompressing data

2) Код сжатия:

#here you can assume the data is the data to be compressed/stored
data = encrypt(zlib.compress(data,9)) #a short wrapper around PyCrypto AES encryption
f = open("somefile", 'wb')
f.write(data)
f.close()

3) Код декомпрессии:

f = open("somefile", 'rb')
data = f.read()
f.close()

zlib.decompress(decrypt(data)) #this yeilds the error in (1)
person Community    schedule 23.08.2009