Итак, у меня есть потоки данных, сжатые функцией zlib.compress () python (2.6). Когда я пытаюсь их распаковать, некоторые из них не распаковываются (ошибка zlib -5, которая кажется «ошибкой буфера», не знаю, что с этим делать). Сначала я подумал, что все готово, но я понял, что все те, которые я не мог распаковать, начинались с 0x78DA (рабочие были 0x789C), и я огляделся и, похоже, это другой вид сжатия zlib - магическое число меняется в зависимости от используемого сжатия. Что я могу использовать для распаковки файлов? Я в шланге?
Распаковка zlib в Python
Ответы (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» указывает на то, что данные, которые вы пытаетесь распаковать, были искажены с момента сжатия. Если это не вызвано использованием текстового режима для файлов, подозрение явно (?) Падает на ваши оболочки для дешифрования и шифрования. Если вам нужна помощь, вам нужно сообщить источник этих оболочек. Фактически, вы должны попытаться (как и я) собрать небольшой скрипт, который воспроизводит проблему более чем в одном входном файле. Во-вторых (как и я) посмотрите, можете ли вы повернуть процесс вспять при каких условиях. Если вам нужна помощь на втором этапе, вам нужно разгласить сценарий воспроизведения проблемы.
Я искал
python -c 'import sys,zlib;sys.stdout.write(zlib.decompress(sys.stdin.read()))'
написал это сам; на основе ответов распаковки zlib в python
Ладно, извини, я недостаточно ясно понял. Это 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 ().
Хорошо, извините за мой последний пост, у меня не было всего. И я не могу редактировать свой пост, потому что не использовал 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)