Pergunta

Eu sou a interface com um servidor que requer que os dados enviados para ele é compactado com Desinflar (algoritmo de Huffman, codificação + LZ77) e também envia dados que eu preciso Inflar.

Eu sei que o Python inclui Zlib, e que as bibliotecas C em Zlib chamadas de suporte para Inflar e Desinflar, mas estes aparentemente não são fornecidos pelo Python Zlib módulo.Ele não dá Comprimir e Descompactar, mas quando eu faço uma chamada, tais como o seguinte:

result_data = zlib.decompress( base64_decoded_compressed_string )

Recebo o seguinte erro:

Error -3 while decompressing data: incorrect header check

O Gzip não há melhor;quando efectuar uma chamada, tais como:

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

Recebo a mensagem de erro:

IOError: Not a gzipped file

o que faz sentido como os dados são um Deflacionado arquivo não é um verdadeiro Arquivo arquivo.

Agora eu sei que existe um Desinflar implementação disponíveis (Pyflate), mas eu não sei de um Inflar implementação.

Parece que existem algumas opções:

  1. Encontrar uma implementação existente (ideal) de Inflar e Desinflar em Python
  2. Escrever a minha própria extensão em Python para o zlib biblioteca c que inclui Inflar e Desinflar
  3. Chamar outra coisa que pode ser executado a partir da linha de comando (como um script do Ruby, desde Inflar/Desinflar chamadas em zlib são totalmente envolto em Ruby)
  4. ?

Estou buscando uma solução, mas à falta de uma solução que irá ser grato por insights, construtivas, opiniões e ideias.

Informações adicionais:O resultado de deflação (e codificação) de uma seqüência de caracteres deve, para os fins de que eu preciso dar o mesmo resultado como o seguinte fragmento de código C#, onde o parâmetro de entrada é um array de bytes de UTF correspondentes aos dados para compactar:

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

Executando isso .LÍQUIDO código para a seqüência de caracteres "desinflar e codificar me" dá o resultado

7b0HYBxJliUmL23Ke39K9UrX4HShCIBgEyTYkEAQ7MGIzeaS7B1pRyMpqyqBymVWZV1mFkDM7Z28995777333nvvvfe6O51OJ/ff/z9cZmQBbPbOStrJniGAqsgfP358Hz8iZvl5mbV5mi1nab6cVrM8XeT/Dw==

Quando "desinflar e codificar me" é executado através do Python Zlib.compress() e, em seguida, codificado em base64, o resultado é "eJxLSU3LSSxJVUjMS1FIzUvOT0lVyE0Fafxhb6k=".

É claro que o zlib.compress() não é uma implementação do algoritmo de mesmo padrão, o algoritmo Deflate.

Mais Informações:

Os 2 primeiros bytes do .NET esvaziar de dados ("7b0HY..."), depois de b64 decodificação são 0xEDBD, que não correspondem a dados Gzip (0x1f8b), BZip2 (0x425A) de dados, ou Zlib (0x789C) de dados.

Os 2 primeiros bytes do Python dados compactados ("eJxLS..."), depois de b64 decodificação são 0x789C.Este é um Zlib cabeçalho.

RESOLVIDO

Para lidar com as matérias desinflar e inflar, sem cabeçalho e a soma de verificação, as seguintes coisas necessárias para acontecer:

No desinflar/compress:tira os dois primeiros bytes (cabeçalho) e os últimos quatro bytes (soma de verificação).

Em inflar/descompactar:há um segundo argumento para o tamanho da janela.Se este valor for negativo, ele suprime cabeçalhos.aqui estão os meus métodos atualmente, incluindo o base64 codificação/decodificação - e a funcionar 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 )
Foi útil?

Solução

Este é um add-on para MizardX a resposta, dando algumas explicações e plano de fundo.

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

De acordo com a RFC 1950, um zlib stream construída no padrão maneira é composto de:

  • uma de 2 bytes de cabeçalho (por exemplo,0x78 0x9C)
  • um desinflar fluxo -- ver RFC 1951
  • uma Adler-32 soma de verificação de dados não compactados (4 bytes)

A C# DeflateStream obras (você adivinhou) uma deflação de fluxo.MizardX do código está dizendo que o zlib módulo que os dados são de uma matéria-prima desinflar fluxo.

Observações:(1) espera-se que o C# "deflação" método de produção de uma seqüência de caracteres mais acontece apenas com curtas de entrada (2) Utilizando as matérias desinflar stream sem Adler-32 soma de verificação?Pouco arriscado, salvo se substituído por algo melhor.

Atualizações

mensagem de erro Block length does not match with its complement

Se você está tentando inflar alguns comprimidos de dados com C# DeflateStream e você receber essa mensagem, então é bem possível que você está dando a ele um um zlib fluxo, não desinflar fluxo.

Ver Como você usar um DeflateStream uma parte de um arquivo?

Copiar e colar a mensagem de erro em uma pesquisa no Google e você vai ter inúmeras ocorrências (incluindo o até a frente da resposta) dizendo praticamente a mesma coisa.

O Java Deflater ...utilizado pelo "site" ...C# DeflateStream "é bastante simples e foi testado contra a implementação de Java".Qual das seguintes possível Java Deflater de construtores é o site usando?

public Deflater(int level, boolean nowrap)

Cria um novo compressor usando o nível de compressão.Se o "nowrap" é verdadeiro, então o ZLIB de cabeçalho e de soma de verificação de campos não serão usados para suportar o formato de compressão usado em ambos o GZIP e no PKZIP.

public Deflater(int level)

Cria um novo compressor usando o nível de compressão.Comprimidos de dados será gerado no ZLIB formato.

public Deflater()

Cria um novo compressor com o padrão do nível de compressão.Comprimidos de dados será gerado no ZLIB formato.

Uma linha de deflater depois de jogar fora os 2 bytes zlib cabeçalho e o 4 bytes de soma de verificação:

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

ou

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

Outras dicas

Você ainda pode usar o zlib módulo para inflar/desviar dados. o gzip O módulo o usa internamente, mas adiciona um cabeçalho de arquivo para transformá-lo em um arquivo gzip. Olhando para o gzip.py Arquivo, algo assim poderia 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

Não sei se isso corresponde exatamente ao que seu servidor exige, mas essas duas funções são capazes de viajar de volta todos os dados que eu tentei.

Os parâmetros são mapeados diretamente para o que é passado para as funções da biblioteca ZLIB.

PitãoC
zlib.compressobj(...)deflateInit(...)
compressobj.compress(...)deflate(...)
zlib.decompressobj(...)inflateInit(...)
decompressobj.decompress(...)inflate(...)

Os construtores criam a estrutura e o preenchem com valores padrão e o passam até as funções init. o compress/decompress métodos atualizam a estrutura e passam para inflate/deflate.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top