Я пишу сценарий, который будет работать с данными, поступающими из инструментов в виде потоков gzip. Примерно в 90% случаев модуль gzip
работает отлично, но некоторые потоки вызывают ошибку IOError: не сжатый файл
. Если заголовок gzip удален, а поток deflate направлен непосредственно в zlib
, я вместо этого получаю Ошибка -3 при распаковке данных: неправильная проверка заголовка
. Примерно через полдня, когда я бился головой об стену, я обнаружил, что потоки, в которых возникают проблемы, содержат кажущееся случайным количество дополнительных байтов (которые не являются частью данных gzip), добавленных в конец.
Мне кажется странным, что Python не может работать с этими файлами по двум причинам:
декомпрессия ОК, завершающий мусор игнорируется
, 7zip завершается успешно.) Документы Gzip и Python, похоже, указывают на то, что это должно работать: (выделено мной)
Должна быть возможность
Мне кажется странным, что Python не может работать с этими файлами по двум причинам:
- И Gzip, и 7zip могут открывать эти "дополненные" файлы без проблем. (Gzip выдает сообщение
, декомпрессия ОК, завершающий мусор игнорируется
, 7zip завершается успешно.)Документы Gzip и Python, похоже, указывают на то, что это должно работать: (выделено мной)
Должна быть возможность
Мне кажется странным, что Python не может работать с этими файлами по двум причинам:
- И Gzip, и 7zip могут открывать эти "дополненные" файлы без проблем. (Gzip выдает сообщение
декомпрессия ОК, завершающий мусор игнорируется
, 7zip завершается успешно.)Документы Gzip и Python, похоже, указывают на то, что это должно работать: (выделено мной)
Должна быть возможность detect the end of the compressed data with any compression method, regardless of the actual size of the compressed data. In particular, the decompressor must be able to detect and skip extra data appended to a valid compressed file on a record-oriented file system, or when the compressed data can only be read from a device in multiples of a определенный размер блока.
Вызов метода
close ()
объектаGzipFile
не закрывает fileobj , , поскольку вы, возможно, захотите добавить больше материала после сжатых данных . Это также позволяет передать объектStringIO
, открытый для записи как fileobj , и получить полученный буфер памяти с помощьюgetvalue ()
методобъекта StringIO
Python
zlib.Decompress.unused_data
:Строка, которая содержит любые байты после конца сжатых данных. То есть он остается
""
до тех пор, пока не станет доступен последний байт, содержащий данные сжатия. Если оказалось, что вся строка содержит сжатые данные, это""
, пустая строка.Единственный способ определить, где заканчивается строка сжатых данных, - это распаковать ее. Это означает, что когда сжатые данные являются частью более крупного файла, вы можете найти его конец, только прочитав данные и введя их с последующей непустой строкой в функцию
decopress ()
объекта декомпрессии. ], пока атрибутunused_data
не станет пустой строкой.Вот четыре подхода, которые я пробовал. (Эти примеры относятся к Python 3.1, но я тестировал 2.5 и 2.7 и имел ту же проблему.)
# approach 1 - gzip.open with gzip.open(filename) as datafile: data = datafile.read() # approach 2 - gzip.GzipFile with open(filename, "rb") as gzipfile: with gzip.GzipFile(fileobj=gzipfile) as datafile: data = datafile.read() # approach 3 - zlib.decompress with open(filename, "rb") as gzipfile: data = zlib.decompress(gzipfile.read()[10:]) # approach 4 - zlib.decompressobj with open(filename, "rb") as gzipfile: decompressor = zlib.decompressobj() data = decompressor.decompress(gzipfile.read()[10:])
Я что-то делаю не так?
ОБНОВЛЕНИЕ
Хорошо, а проблема с
gzip
] кажется ошибкой в модуле, моиzlib
проблемы возникают сами по себе. ; -)Копаясь в
gzip.py
, я понял, что делаю неправильно - по умолчаниюzlib.decompress
et al. ожидайте потоки, обернутые zlib, а не только потоки deflate. Передав отрицательное значение дляwbits
, вы можете указатьzlib
пропустить заголовок zlib и декомпрессировать необработанный поток. Обе эти функции работают:# approach 5 - zlib.decompress with negative wbits with open(filename, "rb") as gzipfile: data = zlib.decompress(gzipfile.read()[10:], -zlib.MAX_WBITS) # approach 6 - zlib.decompressobj with negative wbits with open(filename, "rb") as gzipfile: decompressor = zlib.decompressobj(-zlib.MAX_WBITS) data = decompressor.decompress(gzipfile.read()[10:])