PDA

View Full Version : [JAVA]Compressione dati, calssi Deflater/Inflater


Frank1962
15-05-2007, 10:20
Vi posto il codice che penso sia molto più esplicativo:


import java.io.ByteArrayOutputStream;
import java.util.zip.Deflater;
import java.util.zip.Inflater;




public class Compression {

private byte[] buf = null;
private Deflater compressor = null;
private Inflater decompressor = null;
private ByteArrayOutputStream baos = null;

public Compression() {
buf = new byte[1024];
compressor = new Deflater(Deflater.BEST_COMPRESSION,true);
decompressor = new Inflater(true);
}

public synchronized byte[] Compress(byte[] a) throws Exception {
return Compress(a, null);
}

public synchronized byte[] Compress(byte[] a, byte[] dictionary) throws Exception {
compressor.reset();
if(dictionary!=null)
compressor.setDictionary(dictionary); <---
compressor.setInput(a);
compressor.finish();
baos = new ByteArrayOutputStream(a.length);
while (!compressor.finished()) {
int count = compressor.deflate(buf);
baos.write(buf,0,count);
}
baos.close();
return baos.toByteArray();
}

public synchronized byte[] DeCompress(byte[] a) throws Exception {
return DeCompress(a, null);
}

public synchronized byte[] DeCompress(byte[] a, byte[] dictionary) throws Exception {
decompressor.reset();
if(decompressor.needsDictionary())
decompressor.setDictionary(dictionary);
decompressor.setInput(a);
baos = new ByteArrayOutputStream(a.length);
while (!decompressor.finished()) {
int count = decompressor.inflate(buf);
baos.write(buf,0,count);
}
baos.close();
return baos.toByteArray();
}

}

è una normalissima classe che, dopo essere stata istanziata, permette di comprimere/decomprimere un array di byte: in aggiunta volevo dare l'opzione di potergli passare il dizionario da utilizzare per comprimere i dati in quei casi dove si conosca con buona probabilità quali siano i byte più ricorrenti; il problema è che ogni volta che provo a passargli il dizionario alla riga segnata con la freccetta rossa mi da quest'errore:


java.lang.IllegalArgumentException
at java.util.zip.Deflater.setDictionary(Native Method)
at java.util.zip.Deflater.setDictionary(Unknown Source)
at java.util.zip.Deflater.setDictionary(Unknown Source)
at Compression.Compress(Compression.java:29)


....com'è possibile che l'istanza del Deflater non accetti il dizionario? ...ho controllato, e l'array che gli passo, non è assolutamente un null! :confused:

Frank1962
15-05-2007, 10:38
risolto ....evidentemente l'opzione nowrap che passo ai due costruttori non va daccordo con l'utilizzo del dizionario :D

Frank1962
15-05-2007, 11:06
Questa è la classe finale:


package odbase;

import java.io.ByteArrayOutputStream;
import java.util.zip.Deflater;
import java.util.zip.Inflater;




public class Compression {

private byte[] buf = null;
private byte[] dictionary = null;
private Deflater compressor = null;
private Inflater decompressor = null;
private ByteArrayOutputStream baos = null;

public Compression() {
buf = new byte[1024];
compressor = new Deflater(Deflater.BEST_COMPRESSION,true);
decompressor = new Inflater(true);
}

public Compression(byte[] dictionary) {
buf = new byte[1024];
this.dictionary = dictionary;
compressor = new Deflater(Deflater.BEST_COMPRESSION,false);
decompressor = new Inflater(false);
}

public boolean useDictionary() {
return dictionary!=null;
}

public synchronized byte[] Compress(byte[] a) throws Exception {
compressor.reset();
if(useDictionary())
compressor.setDictionary(dictionary);
compressor.setInput(a);
compressor.finish();
baos = new ByteArrayOutputStream(a.length);
while (!compressor.finished()) {
int count = compressor.deflate(buf);
baos.write(buf,0,count);
}
baos.close();
return baos.toByteArray();
}

public synchronized byte[] DeCompress(byte[] a) throws Exception {
decompressor.reset();
decompressor.setInput(a);
baos = new ByteArrayOutputStream(a.length);
while (!decompressor.finished()) {
int count = decompressor.inflate(buf);
if(decompressor.needsDictionary())
decompressor.setDictionary(dictionary);
baos.write(buf,0,count);
}
baos.close();
return baos.toByteArray();
}

}


Facendo dei test però ho notato che non ho nessun vantaggio nella compressione dei dati ...cioè l'array di byte compressi risulta sempre un poco più grande dell'array di byte compressi utilizzando la normale compressione dei dati senza dizionario!


String dic = "abcdefghyijlmnopqrstuwvz";
Compression c = new Compression(dic.getBytes());
String prova = "wdhgwehwyhbswqyedbwtefdvwteyfdvwtyefcyjetwcfwyefyerfcuywrefuywtrfytwerfvytwerdyfvwerdyuvwterfvdytrehcdfvgcngjaeqwhieywytgbcbwewqiydyugyvketkwcdbkundqeiwrnuweigbcufeehlfhenjfewòfncifuewbfucehrufbvregfyvuberftcyelfucynheòlwruwermefjlrfnvjghbrlweuyòweounhfuwevrbgrelufybwehluefbf";
System.out.println(prova.length());
byte[] aux = c.Compress(prova.getBytes());
System.out.println(aux.length);
aux = c.DeCompress(aux);
System.out.println(aux.length);


Per esempio, in questa situazione se gli passo il dizionario ottengo un array di byte lungo 180 mentre se non gli passo il dizionario ottengo un array lungo 170! :mbe: