Compressione Zip
Molte sorgenti di informazioni contengono dati ridondanti che appesantiscono le comunicazioni fra Client e Server ed in generale fra diversi computer.In questo senso la compressione svolge una funzione molto importante perché a fronte di un piccolo costo di tempo (necessario a comprimere i dati all’origine e a decomprimerli alla sorgente) permette di eliminare tali ridondanze risparmiando risorse di memoria e/o di banda.
Generalmente l’approccio alla compressione di dati può avvenire:
- via software mediante l’applicazione di determinati algoritmi (si pensi ad esempio alla codifica di Huffman)
- via hardware mediante un circuito dedicato allo svolgimenti di tali operazioni

Compressione e decompressione
La operazioni di compressione e decompressione sono l’una l’inverso dell’altra e pertanto sono rappresentabili mediante una black-box bidirezionale.
- lossy che comportano una perdita di dati e quindi una diminuzione della qualità delle informazioni (si pensi ad esempio al formato jpg per le immagini)
- lossless che comprimono i dati senza alcuna perdita e quindi il flusso di informazioni può essere completamente ricostruito
- zip che supporta diversi algoritmi di compressione e sebbene altri formati offrano rapporti di compressione maggiori la sua diffusione gli permette di essere uno dei formati per compressione dati più diffusi
- gzip GNU Zip che fu inizialmente creato da Jean-loup Gailly and Mark Adler ed usa l’algoritmo di Lempel-Ziv
Decompressione dei dati
Per decomprimere un file zip è possibile agire in due distinti modi:- accedendo sequenzialmente a tutti i file compressi all’interno dell’archivio zip
- accedendo in maniera casuale ai file compressi all’interno dell’archivio zip
Accesso sequenziale ai file
L’accesso sequenziale ai file compressi all’interno di un archivio zip e la loro conseguente estrazione si avvale della classe ZipInputStream.Tale classe infatti mediante il metodo getNextEntry() permette di recuperare i punti di accesso dei vari file memorizzati all’interno dell’archivio sottoforma di ZipEntry.
Un oggetto ZipEntry memorizza informazioni relative:
- al nome del file compresso getName()
- alla dimensione del file compresso getCompressedSize()
- al commento associato getComment()
- al metodo di compressione utilizzato getMethod()
- alla dimensione del file non compresso getSize()
- creare uno ZipInputStream associato al file zip da decomprimere
FileInputStream fis = new FileInputStream("filezip.zip"); ZipInputStream zin = new ZipInputStream(new BufferedInputStream(fis));
- identificare i punti di accesso ZipEntry dei vari file memorizzati all’interno ed avviarne l’estrazione
ZipEntry entry; while((entry = zin.getNextEntry()) != null) { ... }
try { BufferedOutputStream output = null; FileInputStream fis = new FileInputStream("filezip.zip"); ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fis)); ZipEntry entry; while((entry = zis.getNextEntry()) != null) { int count; byte dati[] = new byte[1024]; FileOutputStream fos = new FileOutputStream(entry.getName()); output = new BufferedOutputStream(fos, 1024); while ((count = zis.read(dati, 0, 1024))!= -1) { output.write(dati, 0, count); } output.flush(); output.close(); } zis.close(); } catch(Exception e) { ... }
Accesso casuale ai file
Per accedere direttamente ai file compressi all’interno di un archivio zip è possibile ricorrere alla classe ZipFile che è appunto rappresentativa di un archivio zip.La classe ZipFile contiene fra gli altri i metodi:
- getEntry(String name) che permette di recuperare lo ZipEntry relative ad un determinato file (specificato dal nome passato come parametro)
- entries() che restituisce sotto forma di un oggetto Enumeration tutti gli ZipEntry dei file memorizzati all’interno dell’archivio zip
... ZipFile zipfile = new ZipFile("filezip.zip"); Enumeration e = zipfile.entries(); ZipEntry entry = (ZipEntry) zipfile.getEntry("miofile"); BufferedInputStream is = new BufferedInputStream(zipfile.getInputStream(entry)); ...
Compressione dei dati
Analogamente a quanto visto per la decompressione di archivi, la compressione di file in formato zip si avvale della classe ZipOutputStream che permette di ottenere l’OutputStream del file sul quale vogliamo scrivere i nostri dati compressi.FileOutputStream output = new FileOutputStream("filezip.zip"); ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(output));Ottenuto l’oggetto ZipOutputStream occorre aprire un InputStream relativo alla sorgente di dati che vogliamo comprimere:
FileInputStream fi = new FileInputStream(miofile); Creare uno ZipEntry per il file in questione: ZipEntry entry = new ZipEntry(miofile));e registrarlo all’interno del flusso di output sfruttando il metodo putNextEntry(ZipEntry e):
out.putNextEntry(entry);ed infine procedere al salvataggio dei dati mediante la lettura dalla sorgente di input ed il salvataggio nel file di destinazione.
Ecco un esempio completo:
BufferedInputStream input = null; FileOutputStream output = new FileOutputStream("filezip.zip"); ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(output)); out.setMethod(ZipOutputStream.DEFLATED); byte data[] = new byte[1024]; File f = new File(miofile); FileInputStream fi = new FileInputStream(miofile); input = new BufferedInputStream(fi, 1024); ZipEntry entry = new ZipEntry(miofile); out.putNextEntry(entry); int count; while((count = input.read(data, 0, 1024)) != -1) { out.write(data, 0, count); } input.close(); out.close();
Checksum
Molto spesso nelle comunicazioni Client-Server si verificano degli errori di comunicazione: l’interfaccia Checksum (e le sue implementazioni concrete Adler32 e CRC32) definisce appunto una somma di controllo per identificare eventuali errori di trasmissione o di corruzione di file presenti all’interno di un archivio zip.
Tipicamente la Checksum viene aggiunta al flusso di dati e ricalcolata alla sorgente: se le due checksum sono diverse allora i dati ricevuti sono corrotti altrimenti i dati ricevuti non hanno subito errori.
... CheckedOutputStream checksum =new CheckedOutputStream(dest, new Adler32()); ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(checksum)); ...Analogamente per creare uno ZipInputStream è possibile scrivere:
... CheckedInputStream checksum = new CheckedInputStream(fis, new Adler32()); ZipInputStream zis = new ZipInputStream(new BufferedInputStream(checksum)); ...Per recuperare la Checksum da un flusso dati è possibile utilizzare il metodo getChecksum() delle classi CheckedOutputStream e CheckedInputStream.
Compressing and Decompressing Data using Java
Tutorial sul sito della Sun sulla compressione e decompressione in Java.
Tutorial sul sito della Sun sulla compressione e decompressione in Java.
Documentazione java.util.zip
Documentazione sul package java.util.zip contenente le classi per la compressione e decompressione zip.
Documentazione sul package java.util.zip contenente le classi per la compressione e decompressione zip.