Frage

Ich bin mit einem Server miteinander verbunden, bei dem Daten, die an sie gesendet werden Deflate Algorithmus (Huffman Coding + LZ77) und sendet auch Daten, die ich benötigt Aufblasen.

Ich weiß, dass Python ZLIB umfasst und dass die C -Bibliotheken in ZLIB Anrufe unterstützen Aufblasen und Deflate, aber diese werden anscheinend nicht vom Python ZLIB -Modul bereitgestellt. Es bietet Kompresse und Dekomprimieren, aber wenn ich einen Anruf wie folgt tätige:

result_data = zlib.decompress( base64_decoded_compressed_string )

Ich erhalte den folgenden Fehler:

Error -3 while decompressing data: incorrect header check

Gzip macht nicht besser; Bei einem Anruf wie:

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

Ich erhalte den Fehler:

IOError: Not a gzipped file

Was Sinn macht, wenn die Daten a sind Entleert Datei nicht wahr Gziped Datei.

Jetzt weiß ich, dass es eine gibt Deflate Implementierung verfügbar (Pyflate), aber ich weiß nicht eine Aufblasen Implementierung.

Es scheint, dass es einige Optionen gibt:

  1. Finden Sie eine vorhandene Implementierung (Ideal) von Aufblasen und Deflate in Python
  2. Schreiben Sie meine eigene Python -Erweiterung in die ZLIB C -Bibliothek, die enthält Aufblasen und Deflate
  3. Rufen Sie etwas anderes an, das aus der Befehlszeile ausgeführt werden kann (z. B. ein Ruby -Skript, seitdem Aufblasen/Deflate Anrufe in ZLIB sind vollständig in Ruby verpackt)
  4. ?

Ich suche eine Lösung, aber ohne eine Lösung werde ich für Einsichten, konstruktive Meinungen und Ideen dankbar sein.

Zusätzliche Information: Das Ergebnis der Entleerung (und der Codierung). Eine Zeichenfolge sollte für die Zwecke, die ich benötige, das gleiche Ergebnis wie der folgende Ausschnitt von C# Code geben, wobei der Eingabeparameter ein Array von UTF -Bytes ist, die den Daten zu komprimieren: Daten entsprechen:

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;
}

Ausführen dieses .NET -Codes für die Zeichenfolge "Deflatieren und codieren mich" gibt das Ergebnis an

7b0HYBxJliUmL23Ke39K9UrX4HShCIBgEyTYkEAQ7MGIzeaS7B1pRyMpqyqBymVWZV1mFkDM7Z28995777333nvvvfe6O51OJ/ff/z9cZmQBbPbOStrJniGAqsgfP358Hz8iZvl5mbV5mi1nab6cVrM8XeT/Dw==

Wenn "Deflate und Encodes Me" durch die Python zlib.compress () und dann base64 codiert wird, ist das Ergebnis "ejxlsu3lSSXJVUJMS1FIZUVOT0LVYE0FAFXHB6K =".

Es ist klar, dass zlib.compress () keine Implementierung desselben Algorithmus wie der Standard -Deflat -Algorithmus ist.

Mehr Informationen:

Die ersten 2 Bytes der .NET -Deflatendaten ("7B0HY ..."), nach der B64 -Decodierung sind 0xedbd, was nicht den Daten (0x1f8b), BZIP2 (0x425a) Daten oder ZLIB (0x789c) -Daten entspricht.

Die ersten 2 Bytes der Python -komprimierten Daten ("ejxls ..."), nach der B64 -Dekodierung sind 0x789c. Dies ist ein ZLIB -Header.

Gelöst

Um die rohe Deflate zu bewältigen und ohne Kopfball und Kontrollummen aufzublasen, mussten die folgenden Dinge passieren:

Auf Deflate/Compress: Streifen Sie die ersten beiden Bytes (Header) und die letzten vier Bytes (Prüfsumme).

Beim Aufblasen/Dekompress: Es gibt ein zweites Argument für die Fenstergröße. Wenn dieser Wert negativ ist, unterdrückt er Header. Hier sind meine Methoden derzeit, einschließlich der Basis64 -Codierung/-decodierung - und ordnungsgemäß funktionieren:

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 )
War es hilfreich?

Lösung

Dies ist ein Add-On zu Mizardx 'Antwort und gibt einige Erklärungen und Hintergrund.

Sehen http://www.chiramattel.com/george/blog/2007/09/09/deflatestream-block-length-does-not-match.html

Entsprechend RFC 1950, ein ZLIB -Stream, der in standardmäßiger Weise konstruiert ist, besteht aus:

  • Ein 2-Byte-Header (z. B. 0x78 0x9c)
  • ein Deflate Stream - siehe RFC 1951
  • Eine adler-32-Prüfsumme der unkomprimierten Daten (4 Bytes)

Das c# DeflateStream Arbeitet an (Sie haben es erraten) einen Deflate -Stream. Der Code von Mizardx teilt dem ZLIB -Modul mit, dass es sich bei den Daten um einen Rohdeflat -Stream handelt.

Beobachtungen: (1) Man hofft, dass die C# "Deflation" -Methode, die eine längere Zeichenfolge erzeugt, nur mit kurzer Eingabe (2) mit dem Rohdeflat-Stream ohne Adler-32-Prüfsumme erfolgt? Ein bisschen riskant, es sei denn, ersetzt durch etwas Besseres.

Aktualisierung

Fehlermeldung Block length does not match with its complement

Wenn Sie versuchen, einige komprimierte Daten mit dem C# aufzublasen DeflateStream Und Sie erhalten diese Nachricht, dann ist es durchaus möglich, dass Sie ihr einen Zlib -Stream geben, nicht einen Deflate -Stream.

Sehen Wie verwenden Sie einen Deflatestream in einem Teil einer Datei?

Kopieren Sie die Fehlermeldung auch in eine Google -Suche und Sie erhalten zahlreiche Treffer (einschließlich der Vorderseite dieser Antwort).

Die Java Deflater ... verwendet von "der Website" ... C# Deflatestream "ist ziemlich einfach und wurde gegen die Java -Implementierung getestet". Welche der folgenden möglichen Java Deflater Constructors verwendet die Website?

public Deflater(int level, boolean nowrap)

Erstellt einen neuen Kompressor mit dem angegebenen Kompressionsniveau. Wenn 'Nowrap' wahr ist, werden die ZLIB -Header und die Prüfsummenfelder nicht verwendet, um das Komprimierungsformat zu unterstützen, das sowohl in GZIP als auch in PKZIP verwendet wird.

public Deflater(int level)

Erstellt einen neuen Kompressor mit dem angegebenen Kompressionsniveau. Komprimierte Daten werden im ZLIB -Format generiert.

public Deflater()

Erstellt einen neuen Kompressor mit der Standardkomprimierungsstufe. Komprimierte Daten werden im ZLIB -Format generiert.

Ein Einzeilen-Deflater Nachdem Sie den 2-Byte-Zlib-Header und die 4-Byte-Kontrollsumme weggeworfen haben:

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

oder

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

Andere Tipps

Sie können das immer noch verwenden zlib Modul zum Aufblasen/Entleeren von Daten. Das gzip Das Modul verwendet es intern, fügt jedoch einen Dateikopf hinzu, um es in eine Gzip-Datei zu schaffen. Mit Blick auf die gzip.py Datei, so etwas könnte funktionieren:

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

Ich weiß nicht, ob dies genau dem entspricht, was Ihr Server erfordert, aber diese beiden Funktionen können alle Daten, die ich ausprobiert habe, runden.

Die Parameter sind direkt an das, was an die ZLIB -Bibliotheksfunktionen übergeben wird.

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

Die Konstrukteure erstellen die Struktur und füllen sie mit Standardwerten aus und übergeben sie an die Init-Funktionen. Das compress/decompress Methoden aktualisieren die Struktur und geben sie an weiter an inflate/deflate.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top