Я взаимодействую с сервером, который требует, чтобы переданные ему данные были сжаты с помощью алгоритма 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
Gzip не лучше; при совершении вызова, например:
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 script, поскольку вызовы Inflate/Deflate в zlib полностью завернуты в Ruby)
Я ищу решение, но без решения я буду благодарен за идеи, конструктивные мнения и идеи.
Дополнительная информация: Результат дефляции (и кодирования) строки должен для тех целей, которые мне нужны, дать тот же результат, что и следующий фрагмент кода С#, где входным параметром является массив байтов 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 )