Preciso compactar uma String e armazenar em outra String e, se for necessário, preciso que meu código leia a String compactada e descompacte.
O código deste link http://java.sun.com/j2se/1.4.2/docs/api/java/util/zip/Deflater.html faz o que eu preciso, mas se eu resolvo separar a parte que compacta num método e a parte que descompacta em outro, o código passa a não descompactar mais, ou seja, retorna uma String vazia.
private static int quantidade = 0;
public static void main(String[] args) {
String s = compacta("8888887777yyyyeeeeeiiiiaoaoaooooaaaaaa");
System.out.println(s);
System.out.println(descompacta(s, quantidade));
}
public static String compacta(String expressao) {
try {
byte[] input = expressao.getBytes("UTF-8");
byte[] output = new byte[100];
Deflater compresser = new Deflater();
compresser.setInput(input);
compresser.finish();
quantidade = compresser.deflate(output);
return new String(output, 0, quantidade, "UTF-8");
} catch (java.io.UnsupportedEncodingException ex) {
ex.printStackTrace();
return "";
}
}
public static String descompacta(String expressao, int tam) {
try {
byte output[] = expressao.getBytes();
Inflater decompresser = new Inflater();
decompresser.setInput(output, 0, tam);
byte[] result = new byte[100];
int resultLength = decompresser.inflate(result);
decompresser.end();
return new String(result, 0, resultLength, "UTF-8");
} catch (java.io.UnsupportedEncodingException ex) {
ex.printStackTrace();
return "";
} catch (java.util.zip.DataFormatException ex) {
ex.printStackTrace();
return "";
}
}
}[/code]
Existe tbem um tutorial neste site http://www.developer.com/java/other/article.php/10936_3603066_3 usando o algoritmo de Huffman, que tem o mesmo problema.
Se eu invoco o método de compactar e descompactar no mesmo método, é retornado o valor correto, mas se eu resolvo invocar em momentos diferentes, o programa não descompacta, retorna uma String vazia.
Não compacte dados e jogue em uma String; jogue em um byte[]. Isso é porque o construtor de String que recebe um byte[] SEMPRE estraga o byte[] ao tentar convertê-lo para uma String. Isso é “by design” e não tem jeito mesmo.
Se é realmente obrigatório usar uma String (por exemplo, para pôr em um campo VARCHAR em um banco de dados, ou para pôr em um campo HIDDEN em uma página), então você não pode ter dados binários dentro dela; portanto, é necessário codificar o byte[] para uma String usando Base-64.
A codificação Base-64 aumenta um pouco o tamanho dos dados (ou seja, cada 3 bytes são convertidos para 4 caracteres), mas ainda compensa.
Se você realmente não pode aumentar tanto o tamanho dos dados, você pode usar a codificação Base-85, que converte cada 4 bytes para 5 caracteres.
Ou seja:
Processo de compressão:
String -> byte[] -> compressão -> byte[] -> Base-64 -> String
Processo de descompressão:
String -> Base64 -> byte[] -> descompressão -> byte[] -> String
mas o meu problema é que esse código não está descompactando…
se eu pegar esse código todo e colocar tudo num método só, ele compacta e descompacta. Mas se eu deixar em métodos separados (preciso que seja assim), somente compacta e na hora de descompactar retorna uma String vazia…
A minha teoria é que para descompactar, ele precise de algum objeto que foi criado anteriomente.
Preciso muito resolver esse problema.
Mas ainda tem um porém: Quando eu vou compactar usando o método compresser.deflate(output); , tenho que passar como parâmetro um array de bytes com um tamanho pré definido. O problema disso é que ele retorna um monte de AAAAAAAAAAAAA nos espaços que supostamente deveria ser espaços vazios do array, e a String compactada fica maior que a original (em decorrência desse monte de AAAAAAAAA).
eu pensei em retornar um substring, mas não deu certo.
Esse monte de AAAAA é o resultado da conversão dos zeros binários (que foram os bytes não usados pelo compactador ou descompactador) que o Base-64 transformou em AAAAA.
Dica: você não pegou o resultado de “compresser.deflate” ou “decompresser.inflate”. (Veja o javadoc, em http://java.sun.com/javase/6/docs/api/java/util/zip/Inflater.html e http://java.sun.com/javase/6/docs/api/java/util/zip/Deflater.html )
Esse resultado indica quantos bytes foram compactados ou descompactados. Então você passa esse valor da quantidade de bytes para o conversor de Base-64, para que ele não tente converter todos os bytes do buffer (que deve ser um pouco maior que os dados compactados!) e sim apenas a quantidade certa.
Obrigada thingol e Mark_Ameba pelas dicas e eis aqui o código funcionando!!
Encontrei aqui neste mesmo fórum uma dica do thingol para este site: http://commons.apache.org/codec/userguide.html que tem um código de comversão de um array de bytes para Base64.
Como eu não sabia como fazer esse o cálculo para descobrir em quantos caracteres resultariam a conversão, eu abri o código que está no site para download e vi como que o pessoal que programou fez pra calcular.
E ae amigo estou com um problema neste seu algoritmo, ao testa-lo a string retornada depois da descompactação é esta "22101091728000000004000000000000002AGUA OXIG.20 VOL 1000ML LBS "
ou seja ela está faltando conteudo, vc tem alguma ideia do pq isso estar ocorrendo?
Obrigado!
cara aqui deu certo com este while mas se for uma mensagem grande, se eu colocar uma mensagem “teste teste” da erro, tu sabe uma forma de resolver isso?
Cara consegui resolver desta forma, assim independete do tamanho da mensagem ele descompacta.
public static String descompactar(byte[] mensagem) {
byte[] novo = new byte[100];
StringBuffer aux = new StringBuffer();
try {
Inflater dec = new Inflater();
dec.setInput(mensagem);
dec.inflate(novo);
aux.append(new String(novo));
int tam = dec.getTotalIn();
int pos = dec.getTotalOut();
while (pos < tam) {
pos += dec.inflate(novo);
aux.append(new String(novo));
novo = new byte[100];
}
dec.end();
} catch (DataFormatException ex) {
ex.printStackTrace();
}
return aux.toString().trim();
}
Affff!!!
Tinha um erro na minha compactação, Shakall, por isso que as Strings pequenas estavam dando erro!
Agora está aceitando vários tamanhos. Testei com tamanho 1, 20, e aprox. 2000 caracteres.
Acredito que agora não está mais dando erros!