01 сент. 2017 г., 15:44 отmsanfordDemi

Python: Inflate и Deflate реализации

Я взаимодействую с сервером, который требует, чтобы отправляемые на него данные были сжаты с помощью Выкачивает алгоритм (кодировка Хаффмана + LZ77), а также отправляет данные, которые мне нужны, Inflate.

Я знаю, что Python включает Zlib, и что библиотеки C в Zlib поддерживают вызовы Inflate а также Выкачивает, но, очевидно, они не предоставляются модулем Python Zlib. Это обеспечиваетКомпрес а также Decompress, но когда я звоню, например, следующее:

result_data = zlib.decompress( base64_decoded_compressed_string )

Я получаю следующую ошибку:

Error -3 while decompressing data: incorrect header check

Gzip не лучше; при совершении звонка, например:

result_data = gzip.GzipFile( fileobj = StringIO.StringIO( base64_decoded_compressed_string ) ).read()

Я получаю сообщение об ошибке:

IOError: Not a gzipped file

который имеет смысл, так как данные являются Дефлированные файл не настоящий Сжат GZIP файл

Теперь я знаю, что есть Выкачивает реализация доступна (Pyflate), но я не знаю Inflate реализация

Кажется, есть несколько вариантов:

Найти существующую реализацию (идеал) Inflate а также Выкачивает в Python Напишите мое собственное расширение Python для библиотеки zlib c, которое включает в себя Inflate а также Выкачивает Вызовите что-нибудь еще, что может быть выполнено из командной строки (например, скрипт Ruby, так как Inflate/ Выкачивает вызовы в zlib полностью упакованы в Ruby)?

Я ищу решение, но, не имея решения, буду благодарен за идеи, конструктивные мнения и идеи.

Дополнительная информаци: Результат дефлирования (и кодирования) строки должен, для нужных мне целей, дать тот же результат, что и следующий фрагмент кода C #, где входным параметром является массив байтов UTF, соответствующих данным для сжатия:

public static string DeflateAndEncodeBase64(byte[] data)
{
    if (null == data || data.Length < 1) return null;
    string compressedBase64 = "";

    //write into a new memory stream wrapped by a deflate stream
    using (MemoryStream ms = new MemoryStream())
    {
        using (DeflateStream deflateStream = new DeflateStream(ms, CompressionMode.Compress, true))
        {
            //write byte buffer into memorystream
            deflateStream.Write(data, 0, data.Length);
            deflateStream.Close();

            //rewind memory stream and write to base 64 string
            byte[] compressedBytes = new byte[ms.Length];
            ms.Seek(0, SeekOrigin.Begin);
            ms.Read(compressedBytes, 0, (int)ms.Length);
            compressedBase64 = Convert.ToBase64String(,compressedBytes);
        }
    }
    return compressedBase64;
}

Запуск этого кода .NET для строки «выкачать и закодировать меня» дает результат

7b0HYBxJliUmL23Ke39K9UrX4HShCIBgEyTYkEAQ7MGIzeaS7B1pRyMpqyqBymVWZV1mFkDM7Z28995777333nvvvfe6O51OJ/ff/z9cZmQBbPbOStrJniGAqsgfP358Hz8iZvl5mbV5mi1nab6cVrM8XeT/Dw==

Когда «выкачивай и кодируй меня» запускается через Python Zlib.compress (), а затем кодируется в base64, результатом является «eJxLSU3LSSxJVUjMS1FIzUvOT0lVyE0FAFXHB6k =».

Понятно, что zlib.compress () не является реализацией того же алгоритма, что и стандартный алгоритм Deflate.

Больше информаци:

Первые 2 байта данных .NET для дефлятирования ("7b0HY ...") после декодирования b64 равны 0xEDBD, что не соответствует данным Gzip (0x1f8b), данным BZip2 (0x425A) или данным Zlib (0x789C).

Первые 2 байта сжатых данных Python («eJxLS ...») после декодирования b64 равны 0x789C. Это заголовок Zlib.

Решаемые

Чтобы обработать необработанные значения deflate и inflate без заголовка и контрольной суммы, необходимо выполнить следующее:

On deflate / compress: удалить первые два байта (заголовок) и последние четыре байта (контрольная сумма).

На раздув / распаковка: есть второй аргумент для размера окна. Если это значение отрицательно, оно подавляет заголовки. вот мои методы в настоящее время, включая кодирование / декодирование base64 - и работают должным образом:

import zlib
import base64

def decode_base64_and_inflate( b64string ):
    decoded_data = base64.b64decode( b64string )
    return zlib.decompress( decoded_data , -15)

def deflate_and_base64_encode( string_val ):
    zlibbed_str = zlib.compress( string_val )
    compressed_string = zlibbed_str[2:-4]
    return base64.b64encode( compressed_string )

Ответы на вопрос(2)

07 июл. 2009 г., 06:12 отCristian Ciupitu

Ты все еще можешь использоватьzlib модуль для раздувания / выкачивания данных.gzipодуль @ использует его внутри, но добавляет заголовок файла, чтобы превратить его в файл gzip. Глядя наgzip.py file, что-то вроде этого может работать:

import zlib

def deflate(data, compresslevel=9):
    compress = zlib.compressobj(
            compresslevel,        # level: 0-9
            zlib.DEFLATED,        # method: must be DEFLATED
            -zlib.MAX_WBITS,      # window size in bits:
                                  #   -15..-8: negate, suppress header
                                  #   8..15: normal
                                  #   16..30: subtract 16, gzip header
            zlib.DEF_MEM_LEVEL,   # mem level: 1..8/9
            0                     # strategy:
                                  #   0 = Z_DEFAULT_STRATEGY
                                  #   1 = Z_FILTERED
                                  #   2 = Z_HUFFMAN_ONLY
                                  #   3 = Z_RLE
                                  #   4 = Z_FIXED
    )
    deflated = compress.compress(data)
    deflated += compress.flush()
    return deflated

def inflate(data):
    decompress = zlib.decompressobj(
            -zlib.MAX_WBITS  # see above
    )
    inflated = decompress.decompress(data)
    inflated += decompress.flush()
    return inflated

Я не знаю, соответствует ли это в точности тому, что требует ваш сервер, но эти две функции могут обойти все данные, которые я пробовал.

Параметры отображаются непосредственно на то, что передается функциям библиотеки zlib.

PythonC
zlib.compressobj(...)deflateInit(...)
compressobj.compress(...)deflate(...)
zlib.decompressobj(...)inflateInit(...)
decompressobj.decompress(...)inflate(...)

Конструкторы создают структуру, заполняют ее значениями по умолчанию и передают ее функциям init.compress/decompress методы обновляют структуру и передают ее вinflate/deflate.

07 июл. 2009 г., 10:31 отCommunity

содержащее некоторые пояснения и справочную информацию.

Видетьhttp: //www.chiramattel.com/george/blog/2007/09/09/deflatestream-block-length-does-not-match.htm

Согласно с RFC 1950, поток zlib, построенный по умолчанию, состоит из:

2-байтовый заголовок (например, 0x78 0x9C) поток сдувать - см. RFC 1951 контрольная сумма Adler-32 несжатых данных (4 байта)

The C #DeflateStream работает (как вы уже догадались) с потоком deflate. Код MizardX сообщает модулю zlib, что данные являются необработанным потоком сдувания.

Observations: (1) Можно надеяться, что метод "дефляции" C #, создающий более длинную строку, происходит только с коротким вводом (2) Использование необработанного потока deflate без контрольной суммы Adler-32? Немного рискованно, если только не заменить на что-то лучшее.

Обновления

сообщение об ошибкеBlock length does not match with its complement

Если вы пытаетесь надуть сжатые данные с помощью C #DeflateStream и вы получите это сообщение, тогда вполне возможно, что вы даете ему поток zlib, а не поток deflate.

Видеть Как вы используете DeflateStream для части файла?

Также скопируйте / вставьте сообщение об ошибке в поиск Google, и вы получите множество обращений (включая одно в начале этого ответа), говорящих примерно то же самое.

ЯваDeflater ... используемый "веб-сайтом" ... C # DeflateStream "довольно прост и был протестирован с реализацией Java". Какой из следующих возможных конструкторов Java Deflater использует веб-сайт?

public Deflater(int level, boolean nowrap)

Создает новый компрессор, используя указанный уровень сжатия. Если значение «nowrap» равно true, то поля заголовка и контрольной суммы ZLIB не будут использоваться для поддержки формата сжатия, используемого как в GZIP, так и в PKZIP.

public Deflater(int level)

Создает новый компрессор, используя указанный уровень сжатия. Сжатые данные будут сгенерированы в формате ZLIB.

public Deflater()

Создает новый компрессор с уровнем сжатия по умолчанию. Сжатые данные будут сгенерированы в формате ZLIB.

Однострочный дефлятор после удаления 2-байтового заголовка zlib и 4-байтовой контрольной суммы:

uncompressed_string.encode('zlib')[2:-4] # does not work in Python 3.x

ил

zlib.compress(uncompressed_string)[2:-4]

ВАШ ОТВЕТ НА ВОПРОС