У меня есть несколько файлов gz, на которых декомпрессия, похоже, не работает должным образом. Я выбрал один из них, этот файл находится в локальной папке и получен из внешнего источника. Я не знаю процесс сжатия.
Я создал сценарий python, чтобы проиллюстрировать ситуацию. Чтобы иметь ссылочный файл для тестирования, я несжатый gz файл и снова сжал его (используя gzip на Ubuntu), чтобы сгенерировать тот же gz файл на моем компьютере. Эти два файла представляют разные типы поведения:
import gzip
import zlib
import hashlib
def md5(content):
m = hashlib.md5()
m.update(content)
return m.hexdigest()
def decompress_gzip_size(file_name):
with gzip.open(file_name, 'rb') as f_out:
f_content = f_out.read()
print(len(f_content), file_name)
print (md5(f_content), file_name)
def decompress_open_gzip_size(file_name):
with open(file_name, 'rb') as f_out:
f_content = f_out.read()
unzip_content = gzip.decompress(f_content)
print(len(unzip_content), file_name)
print (md5(unzip_content), file_name)
def decompress_zlib_size(file_name):
with open(file_name, 'rb') as f_out:
f_content = f_out.read()
unzip_content = zlib.decompress(f_content, 32)
print(len(unzip_content), file_name)
print (md5(unzip_content), file_name)
def decompress_zlib_obj(file_name):
decompress_obj = zlib.decompressobj(32)
with open(file_name, 'rb') as f_out:
f_content = f_out.read()
unzip_content = decompress_obj.decompress(f_content)
print(len(unzip_content), file_name)
print(len(decompress_obj.unused_data), 'Unused data')
print (md5(unzip_content), file_name)
external_file = 'external_source_compress.gz'
my_file = 'my-compress-file.gz'
print("decompress_gzip_size")
decompress_gzip_size(my_file)
decompress_gzip_size(external_file)
print("*" * 60)
print("decompress_open_gzip_size")
decompress_open_gzip_size(my_file)
decompress_open_gzip_size(external_file)
print("*" * 60)
print("decompress_zlib_size")
decompress_zlib_size(my_file)
decompress_zlib_size(external_file)
print("*" * 60)
print("decompress_zlib_obj")
decompress_zlib_obj(my_file)
decompress_zlib_obj(external_file)
print("*" * 60)
Выход выполнения:
decompress_gzip_size
167019534 my-compress-file.gz
a4dd17dd28b89f0b2c300b607cd1a8ba my-compress-file.gz
167019534 external_source_compress.gz
a4dd17dd28b89f0b2c300b607cd1a8ba external_source_compress.gz
************************************************************
decompress_open_gzip_size
167019534 my-compress-file.gz
a4dd17dd28b89f0b2c300b607cd1a8ba my-compress-file.gz
167019534 external_source_compress.gz
a4dd17dd28b89f0b2c300b607cd1a8ba external_source_compress.gz
************************************************************
decompress_zlib_size
167019534 my-compress-file.gz
a4dd17dd28b89f0b2c300b607cd1a8ba my-compress-file.gz
33408639 external_source_compress.gz
4f51ccc64a7baab5ee5e2ce31e816409 external_source_compress.gz
### SIZES AND MD5 DO NOT MATCH ###
************************************************************
decompress_zlib_obj
167019534 my-compress-file.gz
0 Unused data
a4dd17dd28b89f0b2c300b607cd1a8ba my-compress-file.gz
33408639 external_source_compress.gz
46765202 Unused data
4f51ccc64a7baab5ee5e2ce31e816409 external_source_compress.gz
### THERE IS SOME UNUSED DATA IN THE ORIGINAL FILE ###
************************************************************
ПРИМЕЧАНИЕ. Декомпрессия zlib завершается с ошибкой, если параметры размера окна не превышают 32.
Без установки размера окна это произошло:
Traceback (most recent call last):
File "decompress_python.py", line 53, in <module>
decompress_zlib_size(my_file)
File "decompress_python.py", line 26, in decompress_zlib_size
unzip_content = zlib.decompress(f_content)
zlib.error: Error -3 while decompressing data: incorrect header check
Как видно. Без 32-оконного размера, сбой сценария, но с размером окна 32 он заканчивается, но количество прочитанных байтов - всего лишь часть реального объема данных.
Файл содержит только один элемент:
gzip -l external_source_compress.gz
compressed uncompressed ratio uncompressed_name
58609586 33410520 -75.4% external_source_compress
Может ли кто-нибудь помочь мне понять, что здесь происходит? Я действительно потерян. Заранее спасибо.
Флорианский ответ - это почти наверняка, что происходит, то есть файл gzip, который вы только частично распаковываете, должен иметь несколько членов. Для распаковки следующего члена, вы можете просто получить unused_data
от decompressobj
объекта и запустить другую декомпрессию. Повторяйте, пока не будет использован весь вход.
В этом ответе показан пример обработки файла gzip с несколькими членами в python.
Похоже, то, что вы должны использовать для параметра wbits
равно 31, а не 32. 31 ожидает оболочку gzip в отличие от обертки zlib. Не указывая, что wbits
приводит к распаковке, ожидающей оболочки zlib, поэтому она не работает с вашими потоками gzip.
gzip -l
. Как вы можете видеть, там есть только один файл. Также отрицательная степень сжатия заставляет думать, что с файлом что-то не так. Как вы думаете?
gzip-потоки могут состоять из нескольких элементов, сжатых независимо, которые затем просто объединяются. Ожидается, что декомпрессор в стиле gzip прозрачно считывает все независимо сжатые части, создавая единый выходной поток (в основном игнорируя внутренние индикаторы конца потока).
Документация zlib.compressobj
не говорит об этом, но она остановится при первом обнаружении zlib внутреннего конца потока. Затем оставшиеся данные могут обрабатываться независимо. В некоторых приложениях (но не в вашем) это может быть даже не сжатие zlib-данных.
gzip -l
намного больше, чем размер без сжатия, доказывает, что он должен иметь несколько членов. gzip расширяет несжимаемые данные только на долю процента, поэтому сжатые данные не могут быть намного больше, чем несжатые данные для одного элемента.