Java.util.zip ... Usando os algoritimos da ZLIB

Boa tarde a todos.
Eu estou participando de um projeto, aqui no TRF, desenvolvendo uma pesquisa para consulta de processos. Os dados são inseridos no banco ( CA-Ingres) por uma aplicação Delphi, até ai sem problemas, porém alguem teve uma ideia brilhante de usar a ZLIB para compactar um campo onde se digita um texto longo, e guarda isso em um campo do tipo binary. Bom recuperar esses dados não é o problema. O problema é que eu não estou conseguindo usar a ZLIB do Java para descompactar os dados de um arquivo que eu compactei usando a ZLIB java … Existe um conjunto de classes chamado JZLIB, mas nao tem documentação.
Vou postar aqui o código que eu fiz para compactar e descompactar. A compactação esta funcionando aparentemente, porem quando tente descompatar; aqui no trabalho, esta estourando uma exception OutofMemory, em casa a exception é DataFormatException.
Se alguem já usou essa lib e puder me dar uma ajuda, fico muito grato.

abraços.

Ronaldo.

	File f = new File("c://binario/teste.txt");
	FileInputStream fin = new FileInputStream(f);
	Deflater compressor = new Deflater();
	compressor.setLevel(Deflater.BEST_COMPRESSION);
	byte readByte;
	byte[] in = new byte[(int) f.length()];
	System.out.println(f.length());
	int i = 0;
	StringBuffer sb = new StringBuffer();
	while ((readByte = (byte) fin.read()) != -1) {
		sb.append(String.valueOf((char) readByte));
		in[i++] = readByte;
	}
	fin.close();
	System.out.println(sb.toString());
	
	compressor.setInput(in);
	compressor.finish();
	ByteArrayOutputStream bos = new ByteArrayOutputStream(in.length);

	byte[] buf = new byte[1024];

	while (!compressor.finished()) {
		int count = compressor.deflate(buf);
		bos.write(buf, 0, count);
	}
	try {
		bos.close();
	} catch (IOException e) {
		e.printStackTrace() ;
	}

	// Get the compressed data
	byte[] compressedData = bos.toByteArray();

	try {
		f = new File("c://binario/teste.zip");
		FileOutputStream out = new FileOutputStream(f);
		out.write(compressedData);

		out.flush();
		out.close();

	} catch (Exception e) {
		e.printStackTrace();
	}
	
	// Descompactar ....
	// abrir o zip ...
	fin = new FileInputStream(f);
	in = new byte[(int) f.length()];
	System.out.println(f.length());
	i = 0;
	while ((readByte = (byte) fin.read()) != -1) {
		in[i++] = readByte;
	}
	fin.close();
	
	Inflater decompressor = new Inflater();
    decompressor.setInput(in,0,in.length);

    bos = new ByteArrayOutputStream(in.length);
    buf = new byte[1024];
    while (!decompressor.finished()) {
        try {
            int count = decompressor.inflate(buf);
            bos.write(buf, 0, count);
        } catch (DataFormatException e) {
        	e.printStackTrace() ;
        }
    }
    try {
        bos.close();
    } catch (IOException e) {
    	e.printStackTrace() ;
    }
    // Get the decompressed data
    byte[] decompressedData = bos.toByteArray();
    
	try {
		f = new File("c://binario/teste_out.txt");
		FileOutputStream out = new FileOutputStream(f);
		out.write(decompressedData);
		out.flush();
		out.close();

	} catch (Exception e) {
		e.printStackTrace();
	}

Dica número 0 - por favor, não leia arquivos um byte de cada vez. Aquela função “read()”, que retorna um byte só, é para ser usada em casos muito especificos. Se puder, use o read que lê um byte array de uma vez.

Dica número 1 - sempre que você tiver de fazer algo complicado, veja se não existe uma implementação de referência (no seu caso, o gzip.exe, ou simplesmente gzip em ambiente Unix/Linux). Por exemplo, no seu caso, seria interessante usar GZipInputStream e GZipOutputStream, porque para conferir se está tudo bem, você pode compactar usando GZipOutputStream e jogar o resultado em um arquivo. Se conseguir descompactar usando o gzip, então você sabe que pelo menos está conseguindo compactar corretamente.
Vi o seu código e acho que deve ser alguma coisa boba, mas até descobrir o que está errado com seu código, precisaria debugar…

Ola a todos, e obrigado thingol pelas dicas …
Porem, pior do que ter que fazer algo complicado, é ter que fazer algo “bizarro” … Eu descobri, que não é simplesmente usar a zlib, mas os caras aqui colocaram uns cabeçalhos no arquivo antes de adicionar o conteudo compactado ao arquivo. E eu não estou sabendo fazer o mesmo em Java :frowning:
Eu vou postar aqui as linhas do codigo delphi, derrepente alguem aqui já programou em delphi e sabe como fazer isso em Java … Eu consegui usar a JZLIB, mas o compactando o mesmo arquivo com o Java e com o Delphi, muita coisa fica diferente, eu inclusive comentei as partes no código Delphi que coloca esses cabeçalhos, e tentei comparar com o que foi gerado pelo JZlib, são semelhantes em algumas partes e em outras não … Entao eu gostaria de colocar esses cabeçalhos no arquivo gerado em Java, para saber se o programa Delphi consegue ler.
Qualquer ajuda é super bem vinda !
Grato

Ronaldo.

L: Integer;
FA: integer;
SStr: TFilestream;
TStr: TStream;

L := length(fBackupTitle);
TStr.writeBuffer(L, sizeof(L)); //Size of title
TStr.writeBuffer(PChar(fBackupTitle)^,L); //title
TStr.writeBuffer(fSizeTotal, sizeof(fSizeTotal)); //Total Size of backup
TStr.writeBuffer(fFilesTotal, sizeof(fFilesTotal)); //Total file count
L := length(CurrentFile);
TStr.writeBuffer(L, sizeof(L)); //Size of file name
TStr.writeBuffer(PChar(CurrentFile)^,L); //file name

SStr := TFilestream.create(Currentfile, fmOpenRead or fmShareDenyNone);
FA := FileGetDate(SStr.handle);
TStr.writeBuffer(FA, sizeof(FA)); //file age

E depois de colocar o conteudo do texto compactado …

L := 0;
TStr.writeBuffer(L, sizeof(L)); //end backup

Basicamente são essas as dificuldades que estou tendo …

Uma dica, prefira usar DeflaterOutputStream e InflaterInputStream

Oi Ronaldo,

Valem as dicas do thingol e Eduardo.

Mas parecia interessante seu problema e resolvi experimentar um pouco e acho que o prolema no seu código é a parte onde você lê o arquivo compactado.

i = 0; 
while ((readByte = (byte) fin.read()) != -1) { 
  in[i++] = readByte; 
} 

Não dá, porque fin.read() pode retornar um byte 0xFF/255(que não é muito incomum num conteúdo compactado) e quando você converta para byte, fica -1 e assim seu código acha que encontrou o fim do arquivo.

Precisa usar algo tipo de:

int readInt;
i = 0; 
while ((readInt = fin.read()) != -1) { 
  in[i++] = (byte)readInt; 
} 

Pelo menos assim funcionou para mim.

Mas - repetindo - concordo plenamente com as dicas sugeridas pelos outros.

-Sami

Isso é que dá fazerem formatos proprietários, em vez de usar formatos padrões. Pediram-me para fazer um .zip que pudesse ser quebrado em vários discos. O mais fácil é fazer algo “proprietário”, mas tive a pachorra de ir até o site da PKWARE e baixar a especificação do formato .ZIP com vários discos. Finalmente consegui (sorry, não dá para liberar como open-source), e consegui testar no PKZip, WinZip e PowerArchiver. (Acho que não funciona no Brazip, porque acho que ele usa um formato proprietário também - nada como reinventar a roda… Mas não testei isso.)
Agora você está com problemas, porque para começar, você não sabe se deve passar o parâmetro “nowrap” como true ou false para o construtor da classe Deflater, de forma que fique compatível com o programa Delphi. E por aí vai. (Dica: no seu caso você provavelmente vai ter de usar o Deflater e o Inflater “puros”, não os encapsulamentos com InputStream e OutputStream, e você vai ter de testar com nowrap = true, para ver se fica compatível (nunca fica idêntico) com o programa Delphi.

Bom, vamos lá para mais um capitulo da saga … :lol:

Sami, valeu pela diga, estava realmente acontecendo aquilo que voce mencionou mesmo, mas eu mudei e estou usando o read que le por byte[].
Thingol, o que você disse é a mais pura verdade, os caras ficam inventando essas bizarrices, funciona em uma linguagem e quando você precisa usar em outra, voce se ferra ( meu caso no momento ).
Bom, andei fazendo alguma experiencias, vejam só :

1 - Peguei um programa em delphi que só fazia essa compactação e descompactação bizarra. Comentei todas as linhas onde ele escreve o cabeçalho do arquivo e deixei somente o conteudo compactado ser gravado. Mandei descompactar no codigo Java e bingo ! Funcionou de prima !

2 - Compactei o mesmo arquivo txt duas vezes, um com e outro sem cabeçalho, abri no wordpad e comparei os conteudos e vi onde teoricamente inicia a informação compactada … E vi que se inicia em um determinado byte, ( 120 ou x ).

3 - Fiz um terceiro programinha em Java que começa a ler a partir desse byte para eu poder compor outro byte array para mandar descompactar.
E ai olhem só o que aconteceu …
java.util.zip.DataFormatException: incorrect header check
at java.util.zip.Inflater.inflateBytes(Native Method)
at java.util.zip.Inflater.inflate(Unknown Source)
at java.util.zip.Inflater.inflate(Unknown Source)
at example.Teste7.main(Teste7.java:71)

Ah, e Thingol, eu estou usando o Inflater puro, da java.util.zip.
O fragmento do codigo Java é esse

ByteArrayOutputStream decoded = new ByteArrayOutputStream();
Inflater inflater = new Inflater();
inflater.setInput(temp2)
decoded = new ByteArrayOutputStream();
try {
while (!inflater.finished()) {
datalen = inflater.inflate(temp);
decoded.write(temp, 0, datalen);
}
System.out.write(decoded.toByteArray());
} catch (DataFormatException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

Se alguem tiver uma :idea: eu agradeço muito !

Abraços

Ronaldo.

Ups … falha nossa … :oops: peço desculpas à moderação.

Eu esqueci de remover os bytes que o programa em Delphi grava no final !
Eu arranquei eles e bingo ! Descompactou !

[]´s

Ronaldo.

Parabéns!

.