c# python compression zlib

c# - Python: implementaciones Inflate y Deflate



compression zlib (2)

Aún puede usar el módulo zlib para inflar / desinflar datos. El módulo gzip usa internamente, pero agrega un encabezado de archivo para convertirlo en un archivo gzip. Al mirar el archivo gzip.py , algo como esto podría funcionar:

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

No sé si esto corresponde exactamente a lo que requiera su servidor, pero esas dos funciones pueden redirigir cualquier información que intenté.

Los parámetros se correlacionan directamente con lo que se pasa a las funciones de la biblioteca zlib.

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

Los constructores crean la estructura y la completan con valores predeterminados y la pasan a las funciones de inicio. Los métodos de compress / decompress actualizan la estructura y la pasan para inflate / deflate .

Estoy interactuando con un servidor que requiere que los datos enviados a él estén comprimidos con el algoritmo Deflate (codificación Huffman + LZ77) y también envíe los datos que necesito inflar .

Sé que Python incluye Zlib, y que las bibliotecas de C en Zlib admiten llamadas para inflar y desinflar , pero aparentemente estas no son proporcionadas por el módulo Python Zlib. Proporciona compresión y descompresión , pero cuando hago una llamada como la siguiente:

result_data = zlib.decompress( base64_decoded_compressed_string )

Recibo el siguiente error:

Error -3 while decompressing data: incorrect header check

Gzip no mejora; al hacer una llamada como:

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

Recibo el error:

IOError: Not a gzipped file

lo cual tiene sentido ya que los datos son un archivo desinflado, no un verdadero archivo comprimido .

Ahora sé que hay una implementación de Deflate disponible (Pyflate), pero no sé de una implementación de Inflate .

Parece que hay algunas opciones:

  1. Encuentre una implementación existente (ideal) de inflar y desinflar en Python
  2. Escribir mi propia extensión de Python para la biblioteca zlib c que incluye Inflate y Deflate
  3. Llame a algo más que se pueda ejecutar desde la línea de comandos (como un script de Ruby, ya que las llamadas de Inflate / Deflate en zlib están completamente envueltas en Ruby)
  4. ?

Estoy buscando una solución, pero al carecer de una solución, estaré agradecido por ideas, opiniones constructivas e ideas.

Información adicional : El resultado de desinflar (y codificar) una cadena debe, para los fines que necesito, dar el mismo resultado que el siguiente fragmento de código C #, donde el parámetro de entrada es una matriz de bytes UTF correspondiente a los datos que se comprimirán:

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

Ejecutar este código .NET para la cadena "desinflar y codificarme" da el resultado

7b0HYBxJliUmL23Ke39K9UrX4HShCIBgEyTYkEAQ7MGIzeaS7B1pRyMpqyqBymVWZV1mFkDM7Z28995777333nvvvfe6O51OJ/ff/z9cZmQBbPbOStrJniGAqsgfP358Hz8iZvl5mbV5mi1nab6cVrM8XeT/Dw==

Cuando "desinflar y codificarme" se ejecuta a través de Python Zlib.compress () y luego se codifica en base64, el resultado es "eJxLSU3LSSxJVUjMS1FIzUvOT0lVyE0FAFXHB6k =".

Está claro que zlib.compress () no es una implementación del mismo algoritmo que el algoritmo Deflate estándar.

Más información :

Los primeros 2 bytes de los datos de desinflado .NET ("7b0HY ..."), después de la decodificación b64 son 0xEDBD, que no corresponden a datos Gzip (0x1f8b), datos BZip2 (0x425A) o datos Zlib (0x789C).

Los primeros 2 bytes de los datos comprimidos de Python ("eJxLS ..."), después de la decodificación b64 son 0x789C. Este es un encabezado Zlib.

SOLUCIONADO

Para manejar el desinflado y el inflado crudos, sin encabezado y suma de comprobación, las siguientes cosas deben suceder:

En desinflar / comprimir: elimine los primeros dos bytes (encabezado) y los últimos cuatro bytes (suma de comprobación).

En inflar / descomprimir: hay un segundo argumento para el tamaño de la ventana. Si este valor es negativo, suprime los encabezados. aquí están mis métodos actualmente, incluida la codificación / decodificación base64, y funciona correctamente:

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 )


Este es un complemento a la respuesta de MizardX, dando alguna explicación y antecedentes.

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

De acuerdo con RFC 1950 , una secuencia de zlib construida de la manera predeterminada se compone de:

  • un encabezado de 2 bytes (por ejemplo, 0x78 0x9C)
  • una corriente desinflada - ver RFC 1951
  • una suma de comprobación Adler-32 de los datos sin comprimir (4 bytes)

El C # DeflateStream funciona (lo DeflateStream ) como una corriente desinflada. El código de MizardX le dice al módulo zlib que los datos son una corriente de desinflado sin formato.

Observaciones: (1) Se espera que el método de "desinflación" de C # produciendo una cadena más larga ocurra solo con una entrada corta (2) ¿Usando la corriente de desinflado sin la suma de control Adler-32? Poco arriesgado, a menos que sea reemplazado con algo mejor.

Actualizaciones

mensaje de error La Block length does not match with its complement

Si está tratando de inflar algunos datos comprimidos con el C # DeflateStream y recibe ese mensaje, entonces es muy posible que le esté dando un flujo de zlib, no un flujo desinflado.

Ver ¿Cómo se usa un DeflateStream en una parte de un archivo?

También copie / pegue el mensaje de error en una búsqueda de Google y obtendrá numerosos resultados (incluido el que aparece al principio de esta respuesta) diciendo casi lo mismo.

El Deflater Java ... utilizado por "el sitio web" ... C # DeflateStream "es bastante sencillo y ha sido probado en comparación con la implementación de Java". ¿Cuál de los siguientes posibles constructores de Java Deflater está usando el sitio web?

public Deflater(int level, boolean nowrap)

Crea un nuevo compresor usando el nivel de compresión especificado. Si ''nowrap'' es verdadero, entonces el encabezado ZLIB y los campos de suma de comprobación no se usarán para admitir el formato de compresión utilizado tanto en GZIP como en PKZIP.

public Deflater(int level)

Crea un nuevo compresor usando el nivel de compresión especificado. Los datos comprimidos se generarán en formato ZLIB.

public Deflater()

Crea un nuevo compresor con el nivel de compresión predeterminado. Los datos comprimidos se generarán en formato ZLIB.

Un deflater de una línea después de tirar el encabezado zlib de 2 bytes y la suma de verificación de 4 bytes:

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

o

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