декомпрессия zlib в питоне - PullRequest
9 голосов
/ 22 августа 2009

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

Ответы [ 4 ]

29 голосов
/ 23 августа 2009

Согласно 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' aka Ctrl-Z, а файл читается в текстовом режиме, этот байт и все последующие байты НЕ будут включены в сжатый файл, и, таким образом, НЕ может быть восстановлено. Для текстового файла (например, исходного кода) это совсем не потеря. Для бинарного файла вы, скорее всего, используете.

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

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

3 голосов
/ 21 июля 2017

Я искал

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

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

0 голосов
/ 24 августа 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)
0 голосов
/ 23 августа 2009

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

...