Различное поведение для процесса распаковки файлов gz

1

У меня есть несколько файлов 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

Может ли кто-нибудь помочь мне понять, что здесь происходит? Я действительно потерян. Заранее спасибо.

  • 1
    Тот факт, что сжатый размер, указанный в gzip -l намного больше, чем размер без сжатия, доказывает, что он должен иметь несколько членов. gzip расширяет несжимаемые данные только на долю процента, поэтому сжатые данные не могут быть намного больше, чем несжатые данные для одного элемента.
Теги:
compression
zip
gzip

2 ответа

2
Лучший ответ

Флорианский ответ - это почти наверняка, что происходит, то есть файл gzip, который вы только частично распаковываете, должен иметь несколько членов. Для распаковки следующего члена, вы можете просто получить unused_data от decompressobj объекта и запустить другую декомпрессию. Повторяйте, пока не будет использован весь вход.

В этом ответе показан пример обработки файла gzip с несколькими членами в python.

Похоже, то, что вы должны использовать для параметра wbits равно 31, а не 32. 31 ожидает оболочку gzip в отличие от обертки zlib. Не указывая, что wbits приводит к распаковке, ожидающей оболочки zlib, поэтому она не работает с вашими потоками gzip.

  • 0
    Спасибо Марк. Я на самом деле не ищу решение в Python. Я пытаюсь обойти это поведение для некоторых gzip в Java / Scala, я просто хочу понять, почему это происходит. Сценарий Python - это просто способ объяснить ситуацию. Почему wbits определяет формат файла? Это странно для меня.
  • 0
    Я добавил вывод файла gzip -l . Как вы можете видеть, там есть только один файл. Также отрицательная степень сжатия заставляет думать, что с файлом что-то не так. Как вы думаете?
Показать ещё 5 комментариев
1

gzip-потоки могут состоять из нескольких элементов, сжатых независимо, которые затем просто объединяются. Ожидается, что декомпрессор в стиле gzip прозрачно считывает все независимо сжатые части, создавая единый выходной поток (в основном игнорируя внутренние индикаторы конца потока).

Документация zlib.compressobj не говорит об этом, но она остановится при первом обнаружении zlib внутреннего конца потока. Затем оставшиеся данные могут обрабатываться независимо. В некоторых приложениях (но не в вашем) это может быть даже не сжатие zlib-данных.

  • 0
    Спасибо за ваш ответ, это действительно полезно. Не могли бы вы попытаться объяснить мне ошибку размера окна? Я отредактировал вопрос, чтобы добавить больше деталей.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню