Реализации Python: Inflate и Deflate
Я взаимодействую с сервером, который требует, чтобы данные, отправленные на него, были сжаты с помощью алгоритма Deflate (кодировка Хаффмана + LZ77), а также отправили данные, которые мне нужно надуть .
Я знаю, что Python включает Zlib и что библиотеки C в Zlib поддерживают вызовы Inflate и Deflate , но они, по-видимому, не предусмотрены модулем Python Zlib. Он обеспечивает сжатие и декомпрессию , но когда я звоню, например, следующее:
result_data = zlib.decompress( base64_decoded_compressed_string )
Я получаю следующую ошибку:
Error -3 while decompressing data: incorrect header check
Гзип не лучше; при звонке, например:
result_data = gzip.GzipFile( fileobj = StringIO.StringIO( base64_decoded_compressed_string ) ).read()
Я получаю сообщение об ошибке:
IOError: Not a gzipped file
что имеет смысл, поскольку данные являются дефлированным файлом, а не истинным файлом Gzipped .
Теперь я знаю, что существует реализация Deflate (Pyflate), но я не знаю о внедрении Inflate .
Кажется, есть несколько вариантов:
- Найдите существующую реализацию (идеальную) Inflate и Deflate в Python
- Напишите мое собственное расширение Python для библиотеки zlib c, которая включает в себя Inflate и Deflate
- Вызовите что-нибудь другое, которое может быть выполнено из командной строки (например, скрипт Ruby, поскольку вызовы Inflate / Deflate в 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-кода для строки «deflate and encode me» дает результат
7b0HYBxJliUmL23Ke39K9UrX4HShCIBgEyTYkEAQ7MGIzeaS7B1pRyMpqyqBymVWZV1mFkDM7Z28995777333nvvvfe6O51OJ/ff/z9cZmQBbPbOStrJniGAqsgfP358Hz8iZvl5mbV5mi1nab6cVrM8XeT/Dw==
Когда «deflate and encode me» запускается через 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 / 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 )
- LZ77 сжатые зарезервированные байты "<,>"
- Библиотека изображений Python (PIL), как сжать изображение в желаемый размер файла?
- сжатие огромного набора аналогичных строк
- Загрузка большого файла в ошибку python: сжатый файл закончился до того, как был достигнут маркер конца потока
- Django: сжатие данных TextField (string) на уровне базы данных или уровне кода
Это дополнение к ответу MizardX, дающее некоторые объяснения и предысторию.
См. http://www.chiramattel.com/george/blog/2007/09/09/deflatestream-block-length-does-not-match.html.
Согласно RFC 1950 , поток zlib, построенный по умолчанию, состоит из:
- 2-байтовый заголовок (например, 0x78 0x9C)
- поток спускания – см. RFC 1951
- контрольная сумма Adler-32 несжатых данных (4 байта)
C # DeflateStream
работает (как вы уже догадались) потоком DeflateStream
. Код MizardX сообщает модулю zlib, что данные являются сырым потоком дефлята.
Наблюдения: (1) Можно надеяться, что метод C # «дефляция», производящий более длинную строку, происходит только с коротким входом (2) Используя поток сыпучего дефлята без контрольной суммы Adler-32? Бит рискован, если не заменить что-то лучше.
Обновления
сообщение об ошибке Block length does not match with its complement
Если вы пытаетесь раздуть некоторые сжатые данные с помощью C # DeflateStream
и вы получите это сообщение, то вполне возможно, что вы даете ему поток al zlib, а не поток спускания.
См. Как вы используете DeflateStream на части файла?
Также скопируйте / вставьте сообщение об ошибке в поиск Google, и вы получите многочисленные хиты (в том числе и тот, который стоит перед этим ответом), говорящий примерно то же самое.
Java Deflater
… используемый «сайтом» … C # DeflateStream «довольно прост и протестирован против реализации Java». Каким из следующих возможных конструкторов Java Deflater является использование веб-сайта?
public Deflater(int level, boolean nowrap)
Создает новый компрессор с использованием указанного уровня сжатия. Если «nowrap» истинно, поля заголовка 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]
Вы можете использовать модуль zlib
для раздувания / дефляции данных. Модуль gzip
использует его внутренне, но добавляет заголовок файла, чтобы превратить его в gzip-файл. Глядя на файл gzip.py
, что-то вроде этого может работать:
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.
Python ⇒ C
zlib.compressobj(...)
⇒ deflateInit(...)
compressobj.compress(...)
⇒ deflate(...)
zlib.decompressobj(...)
⇒ inflateInit(...)
decompressobj.decompress(...)
⇒ inflate(...)
Конструкторы создают структуру и заполняют ее значениями по умолчанию и передают их в init-functions. Методы compress
/ decompress
обновляют структуру и передают ее для inflate
/ deflate
.
- Сценарий Python, чтобы делать что-то в одно и то же время каждый день
- Видя escape-символы при нажатии клавиш со стрелками в оболочке python
- Как сжать папку с помощью модуля Python GZip?
- Сжатие DXT для Python
- Python – извлечение файлов из большого (6GB +) zip-файла
- Сжатие объекта Python в памяти
- Декомпрессия с помощью PyLZMA
- Как определить, сжат ли файл gzip?
- Как перечислить содержимое файла gzip без его извлечения в python?
- Минимизировать / сжать javascript и css при развертывании в webapp2?
- Как перечислить содержимое gz-файла без его извлечения в python?