Python: implementacje Inflate i Deflate
Łączę się z serwerem, który wymaga, aby przesyłane do niego dane były skompresowaneSiadać algorytm (kodowanie Huffmana + LZ77), a także wysyła dane, których potrzebujęNadmuchać.
Wiem, że Python zawiera Zlib i że biblioteki C w Zlib obsługują wywołaniaNadmuchać iSiadać, ale najwyraźniej nie są one dostarczane przez moduł Python Zlib. To zapewniaKompres iRozprężać, ale kiedy wykonuję połączenie, takie jak:
result_data = zlib.decompress( base64_decoded_compressed_string )
Otrzymuję następujący błąd:
Error -3 while decompressing data: incorrect header check
Gzip nie robi nic lepszego; podczas wykonywania połączenia, takiego jak:
result_data = gzip.GzipFile( fileobj = StringIO.StringIO( base64_decoded_compressed_string ) ).read()
Otrzymuję błąd:
IOError: Not a gzipped file
co ma sens, ponieważ dane sąDeflated plik nie jest prawdąGzipped plik.
Teraz wiem, że jestSiadać dostępna implementacja (Pyflate), ale nie wiemNadmuchać realizacja.
Wydaje się, że istnieje kilka opcji:
Znajdź istniejącą implementację (ideał)Nadmuchać iSiadać w PythonieNapisz moje własne rozszerzenie Pythona do biblioteki zlib c, która zawieraNadmuchać iSiadaćWywołaj coś innego, które można wykonać z wiersza poleceń (np. Skrypt Ruby, ponieważNadmuchać/Siadać wywołania w zlib są całkowicie zapakowane w Ruby)?Szukam rozwiązania, ale bez rozwiązania będę wdzięczny za spostrzeżenia, konstruktywne opinie i pomysły.
Dodatkowe informacje: W wyniku deflacji (i kodowania) ciągu znaków, dla potrzeb, których potrzebuję, dać taki sam wynik, jak następujący fragment kodu C #, gdzie parametrem wejściowym jest tablica bajtów UTF odpowiadająca danym do skompresowania:
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;
}
Uruchomienie tego kodu .NET dla ciągu „deflate and encode me” daje wynik
7b0HYBxJliUmL23Ke39K9UrX4HShCIBgEyTYkEAQ7MGIzeaS7B1pRyMpqyqBymVWZV1mFkDM7Z28995777333nvvvfe6O51OJ/ff/z9cZmQBbPbOStrJniGAqsgfP358Hz8iZvl5mbV5mi1nab6cVrM8XeT/Dw==
Gdy „deflate and encode me” jest uruchamiany przez kodowanie Plix Zlib.compress () a następnie base64, wynikiem jest „eJxLSU3LSSxJVUjMS1FIzUvOT0lVyE0FAFXHB6k =”.
Jasne jest, że zlib.compress () nie jest implementacją tego samego algorytmu, co standardowy algorytm Deflate.
Więcej informacji:
Pierwsze 2 bajty danych deflacji .NET („7b0HY ...”) po dekodowaniu b64 to 0xEDBD, które nie odpowiadają danym Gzip (0x1f8b), danych BZip2 (0x425A) lub danych Zlib (0x789C).
Pierwsze 2 bajty skompresowanych danych Pythona („eJxLS ...”) po dekodowaniu b64 to 0x789C. To jest nagłówek Zlib.
ROZWIĄZANY
Aby obsłużyć surową deflację i nadmuchać, bez nagłówka i sumy kontrolnej, należy wykonać następujące czynności:
W deflate / compress: usuń pierwsze dwa bajty (nagłówek) i ostatnie cztery bajty (sumę kontrolną).
Po nadmuchaniu / dekompresji: istnieje drugi argument dotyczący rozmiaru okna. Jeśli ta wartość jest ujemna, pomija nagłówki. oto moje metody obecnie, w tym kodowanie / dekodowanie base64 - i działające poprawnie:
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 )