Compressão de dados

Haveria alguma maneira de comprimir arrays de bytes com uma compressao melhor do que a utilizada pela classe Deflater do pacote java.util.zip?

Ter tem, é só procurar alguma implementação Java ou JNI de algum outro algoritmo, tal como o utilizado pelo BZIP2.

Mas em termos de compressão, qual é o melhor?

A resposta é “depende”. Por exemplo, se no seu caso você quer comprimir objetos serializados (é isso mesmo que você quer?), então qualquer algoritmo que faça compressão “sem perdas” é razoável, já que o tamanho dos objetos é relativamente pequeno.
O próprio algoritmo Deflate, do java.util.zip já é muito bom para isso.
Se o objeto tiver muitos bytes repetidos, você pode primeiro aplicar RLE, depois aplicar Deflate (experimente comprimir um arquivo de 10 MB somente com zeros binários usando apenas Deflate, para comprovar o que estou falando).
Talvez seja necessário usar algum outro recurso para diminuir um pouco o tamanho dos dados transmitidos via serialização, que acho que é o que você quer.
Por exemplo, se você conseguir juntar vários objetos e comprimi-los todos de uma vez, obterá uma compressão melhor que se comprimir um por um.
É como você comprimir arquivos usando .zip (cada arquivo é comprimido separadamente) ou usando .tar.gz (primeiro os arquivos são juntados, a seguir são comprimidos todos de uma vez). O algoritmo é exatamente o mesmo para os dois casos (Deflate), mas normalmente arquivos .tar.gz são um pouco menores. Isso é levado ao extremo pelo compressor 7-Zip (que basicamente tenta reordenar os arquivos de modo que arquivos parecidos fiquem juntos, para que a compressão seja a melhor possível).
Se você quer comprimir imagens com perdas, há diversos algoritmos (como os usados pelo JPEG); assim como sons com perdas (o famoso algoritmo MPEG usado no MP3), ou vídeos com perdas (MPEG-4, etc).

Bom, a minha idéia no geral é a seguinte, no projeto do trabalho teremos que gerar um código de barras no formato pdf417 que comporta até 2700 caracteres (aqui tem uma foto do código: http://pdf417.dlawas.com/przyklad2.gif. Então, nesse código de barras eu teria que passar uma chave pública, a assinatura digital e o arquivo assinado… Eu estava pensando em passar todos essas informações em um array de bytes grande, tendo cada informação separada por tokens, mas não estou conseguindo um resultado muito satisfatório, usando a compressão deflate… Ao passar um objeto a um array de bytes e depois comprimir esse array, ele passa de 950 pra 870 bytes (cada item do array), o arquivo é um documento xml, que até consegue uma boa compressão de 2300 passa pra 650 bytes e a assinatura possui 256 bytes e cada token possui 3 bytes… O problema eh que teria que eu estou passando para uma string hexadecimal e cada eu faça isso, irá dobrar o tamanho da saída… Sugestões do que fazer?

Bom, hexadecimal está fora de questão nesse caso (já que duplica o tamanho de seus dados). “Joga fora no lixo!”
Use uma codificação melhor.
Parece que dependendo do leitor ( http://www.bizfonts.com/pdf417/faq.html ) é possível até codificar 256 símbolos possíveis ( = 1 byte), ou seja, não seria preciso a conversão de dados.
Mas como 256 símbolos podem dar problemas, é melhor usar Base-64 (converte 3 bytes em 4 caracteres; usado normalmente em certificados digitais, como você já deve ter visto), ou Base-85 (converte 4 bytes para 5 caracteres; usado no Adobe Postscript para transmitir dados para algumas impressoras que não aceitam dados com 8 bits; você pode até encontrar alguns arquivos .PDF que são codificados dessa maneira.)
Base-64 tem pronto no http://jakarta.apache.org/commons , e Base-85 não é difícil de codificar também (fiz um em Javascript, que é meio complicado para trabalhar com bits ou fazer contas com números inteiros; em Java seria muito mais fácil).
E XML é realmente muito “gastão” - ainda bem que seu compressor está funcionando bem com os dados XML que você está lhe fornecendo.

bom, valeu por tudo ae, vou ver se utilizo o base64, espero que resolva os meus problemas ;), ah, poderias disponibilizar a fonte do base85 que tu fez?

Hum, quanto ao Base-85 não posso pôr o fonte aqui (aqueles famosos contratos de confidencialidade etc.)

Mas não é excessivamente difícil de fazer.

Basicamente para decodificar um dado que foi escrito em Base-85, é necessário quebrar o dado em conjuntos de 5 caracteres, então procurar cada caracter em uma tabela (‘A’ = 0, ‘B’ = 1 etc.), que retorna um número de 0 a 84. Deve-se então acumular os números (multiplicando o número anterior por 85 e adicionar o número obtido), até obter um inteiro que tem o comprimento de 4 bytes.

Para codificar, deve-se efetuar o processo inverso (ir dividindo por 85 e ir pegando o resto etc.)

mas uma coisa, com base64 o meu array de bytes quando encodado diminuiria de tamanho ao passa-lo pra uma string?

Quando convertemos um array de bytes para Base-64, cada 3 bytes são convertidos para 4 caracteres.

Quando convertemos uma string Base-64 para um array de bytes, cada 4 caracteres são convertidos para 3 bytes.

Então, no meu caso eu precisaria de uma string menor para enviar para o codigo de barras

entendi agora, realmente diminui, heheh valeu :smiley:

uma coisa, haveria na internet alguma implementação do algoritmo bzip2 para o java? onde eu poderia encontrar um texto explicativo sobre base85?

Ué… quem sabe? Ahhh, mas se nós procurarmos no google descobriremos… Fui no google e procurei por: bzip2 java

http://www.google.com/search?hl=en&q=bzip2+java&btnG=Google+Search

Com uma rápida olhada nos resultados, tem um que pode ser interessante:

:arrow: bzip2 library from Apache Ant

Se esse não for interessante, basta dar uma outra olhada nos resultados! :smiley:

po, valeu ae cara, mto obrigado msm

Uma coisa, pra comprimir arquivos xml, o q vocês recomendariam?

Bom, eu recomendaria não usar XML se você tem problemas com tamanho - mesmo compactado o XML ainda é muito gastão.
Mas se ambos os lados (cliente e servidor) sabem exatamente quais são os dados a serem trocados e a aplicação não precisa ser flexível, pode-se tentar algum método como “Fast Web Services” (procure no site da Sun o que é isso, nem sei se isso já está pronto para ser usado. Na verdade o nome é só um argumento de venda; a intenção do “Fast Web Services” é a recodificação do XML em uma codificação do ASN.1 chamada PER - não é indicado para estômagos mais sensíveis.)
No seu caso um método tradicional de compressão acho que já dá para o gasto. Só testar e ver.

O problema do meu projeto, eh que eu teria que por o conteudo do xml num código de barras, já tentei de tudo heh

Tudo é questão de reavaliar os requisitos quando não é possível implementá-los.
Por exemplo, se mesmo comprimindo o XML e codificando-o para Base-85 não é possível incluir no código de barras, pode-se ver se é possível eliminar a exigência de usar XML e usar em seu lugar um código separado por vírgulas, ou um código posicional (tal como os códigos usados em EDI).

Poderias me dizer um pouco mais sobre esse EDI?
A compressão até que é boa, de um arquivo de 2400 bytes passa pra uns 650, já tentei com várias, bzip2, gzip, zip e a ke obtive melhor resultado foi com a deflate