Compression avec l'API Zip de Java

Hugo ETIEVANT

Compression avec l'API Zip de Java

Télécharger les sources des exemples du tutoriel

- Titre : Compression avec l'API Zip de Java

- Auteur : Hugo ETIEVANT

- Parution : 20 juin 2004

- Licence : Copyright ® 2004 Hugo ETIEVANT. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- II. Présentation de l'API Zip

- III. Compression

- III-A. Fichier de sortie

- III-B. Paramètres

- III-C. Entrées de l'archive

- III-D. Écriture de l'archive

- IV. Listage des entrées d'une archive

- V. Propriétés d'une entrée

- VI. Ratio

- VII. Date

- VIII. Méthode

- IX. Qualité de la compression

- X. Décompression

- X-A. Fichiers d'entrée

- X-B. Écriture

- X-C. Fermeture

- XI. Checksums

- XII. Accents

- XIII. Méthode rapide : ZipFile

- XIV. Historique

- XV. Note et remerciement du gabarisateur

I - Introduction

Un programme informatique manipule souvent des fichiers dont certains doivent être compressés du fait de leur volume ou par souci de créer une archive unique facilement distribuable.

Le format Zip est largement répandu, son algorithme est simple et libre.

II - Présentation de l'API Zip

L'API Zip de Java est présente dans le JDK depuis la version 1.1.

Elle permet de manipuler des fichiers au format Zip et GZip. L'algorithme utilisé est la méthode DEFLATE. Cette API fournit également des méthodes utilitaires pour le contrôle de l'intégrité des fichiers via les méthodes CRC-32 et Adler-32.

Cette API s'appelle de cette façon :

import java.util.zip.*;

III - Compression

La compression nécessite de connaître :

- le ou les fichiers à compresser ;

- le nom de l'archive à créer ;

- la méthode de compression (optionnelle) ;

- le taux de compression (optionnelle).

III-A - Fichier de sortie

- Une valeur de taille de tampon pour les buffers d'entrée et de sortie utilisés par la suite, et un buffer de données :

static final int BUFFER = 2048;
byte data[] = new byte[BUFFER];

- Création d'un flux d'écriture vers un fichier, ce fichier sera l'archive Zip finale :

FileOutputStream dest= new FileOutputStream("archive.zip");

- Création d'un buffer de sortie afin d'améliorer les performances d'écriture :

BufferedOutputStream buff = new BufferedOutputStream(dest);

- Création d'un flux d'écriture Zip vers ce fichier à travers le buffer :

ZipOutputStream out = new ZipOutputStream(buff);

III-B - Paramètres

- Spécifier la méthode de compression désirée :

out.setMethod(ZipOutputStream.DEFLATED);

- Spécifier le taux de compression (entier positif entre 0 et 9) :

out.setLevel(9);

III-C - Entrées de l'archive

- Lister les fichiers à compresser. Dans notre exemple, ils sont supposés être dans le tableau files[] :

for(int i=0; i<files.length; i++) {
FileInputStream fi = new FileInputStream(files[i]);
&#8230;

- Leur créer un buffer d'entrée :

BufferedInputStream buffi = new BufferedInputStream(fi, BUFFER);

- Pour chacun d'eux, créer une entrée Zip :

ZipEntry entry= new ZipEntry(files[i]));

- Et affecter cette entrée au flux de sortie :

out.putNextEntry(entry);

III-D - Écriture de l'archive

- Écriture des entrées dans le flux de sortie par paquets de taille égale aux tampons d'entrée et de sortie :

int count;
while((count = buffi.read(data, 0, BUFFER)) != -1) {
out.write(data, 0, count);
}

- Fermeture de l'entrée en cours :

out.closeEntry();

- Fermeture des flux :

buffi.close();
}
out.close();

Et voilà, votre archive Zip est créée. Elle pourra être décompressée avec WinZip (Windows) ou unzip (Unix).

IV - Listage des entrées d'une archive

Pour lister le contenu d'une archive Zip et en afficher les propriétés il faut procéder ainsi :

- ouverture du fichier Zip :

ZipFile zf = new ZipFile("archive.zip");

- extraction de ses entrées :

Enumeration entries = zf.entries()

- parcours de chacune des entrées :

while(entries.hasMoreElements()) {
ZipEntrye = (ZipEntry)entries.nextElement();
&#8230;

- extraction des informations désirées :

System.out.println(e.getName());
}

Et voilà !

V - Propriétés d'une entrée

Méthode

Description

String getComment()

Retourne le commentaire associé à l'entrée, null si aucun

long getCompressedSize()

Retourne la taille de l'entrée après compression, -1 si inconnue

long getCrc()

Retourne le contrôle d'erreur cyclique CRC ou -1 si inconnu

byte[] getExtra()

Retourne le champ optionnel ou -1 si inconnu

int getMethod()

Retourne la méthode de compression employée, -1 si inconnue

String getName()

Retourne le nom de l'entrée

long getSize()

Retourne la taille de l'entrée avant compression, -1 si inconnue

long getTime()

Retourne la date et heure de dernière modification, -1 si inconnue

int hashCode()

Retourne le hashcode (condensat) de cette entrée

boolean isDirectory()

Retourne vrai (true) si l'entrée est un répertoire

String toString()

Retourne une représentation de l'entrée sous forme de chaîne de caractères

Les getters précédents ont leurs setters associés ci-bas :

Méthode

Description

void setComment(String c)

Affectation du commentaire associé à l'entrée

void setCompressedSize(long csize)

Affectation de la taille de l'entrée après compression

void setCrc(long crc)

Affectation du CRC de l'entrée

void setExtra(byte[] extra)

Affectation d'un champ optionnel

void setMethod(int method)

Affectation d'une méthode de compression à l'entrée

void setSize(long size)

Affectation de la taille de l'entrée avant compression

void setTime(long time)

Affectation de la date et heure de dernière modification

VI - Ratio

Le calcul du ratio s'effectue ainsi :

Exemple :

System.out.println(e.getName() + " ratio: " + ((e.getSize() - e.getCompressedSize()) * 100) / e.getSize() + "%");

VII - Date

La date est au format TimeStamp (nombre de secondes écoulées entre la date et le 1er janvier 1970), il est alors nécessaire de la formater au format voulu (ici, francophone).

Exemple :

DateFormat df = new SimpleDateFormat("dd/mm/yyyy hh:mm:ss");
Dated = null;
d = new Date(e.getTime());
System.out.println(" date: " + df.format(d));

VIII - Méthode

Il n'existe que deux méthodes : DEFLATED (avec compression) et STORED (sans compression).

Exemple :

String method = null;
if (e.getMethod() == ZipEntry.DEFLATED) {
method = new String("DEFLATED");
} else if(e.getMethod() == ZipEntry.STORED) {
method = new String("STORED");
}

IX - Qualité de la compression

Il existe 10 niveaux, numérotés de 0 à 9.

Il existe aussi des constantes :

Constante

Description

Niveau

Deflater.BEST_COMPRESSION

Meilleure compression

9

Deflater.DEFAULT_COMPRESSION

Compression par défaut

5

Deflater.BEST_SPEED

Meilleure rapidité

1

Deflater.NO_COMPRESSION

Pas de compression

0

Exemple :

out.setLevel(Deflater.BEST_COMPRESSION);

X - Décompression

X-A - Fichiers d'entrée

- Une valeur de taille de tampon pour les buffers d'entrée et de sortie utilisés par la suite, et un buffer de données :

static final int BUFFER = 2048;
byte data[] = new byte[BUFFER];

- Déclaration d'un fichier destination :

BufferedOutputStream dest = null;

- Ouverture du fichier à décompresser :

FileInputStream fis = new FileInputStream("archive.zip");

- Ouverture buffer sur ce fichier :

BufferedInputStream buffi = new BufferedInputStream(fis);

- Ouverture de l'archive Zip via ce buffer :

ZipInputStream zis = new ZipInputStream(buffi);

X-B - Écriture

- Parcours des entrées de l'archive :

ZipEntry entry;
while((entry = zis.getNextEntry()) != null) {
&#8230;

- Création du fichier de sortie à partir du nom de l'entrée :

FileOutputStream fos = new FileOutputStream(entry.getName());

- Affectation au buffer de sortie de ce flux vers fichier :

dest = new BufferedOutputStream(fos, BUFFER);

- Écriture sur disque :

while ((count = zis.read(data, 0, BUFFER)) != -1) {
dest.write(data, 0, count);
}

X-C - Fermeture

- Vidage du tampon en écriture :

dest.flush();

- Fermeture du flux de sortie :

dest.close();
}

- Fermeture de l'archive :

zis.close();

XI - Checksums

Pour inclure un contrôle d'intégrité dans vos applications, il faut ajouter un flux de contrôle entre le flux d'écriture sur fichier et le flux du buffer de sortie. Il existe deux méthodes de contrôle : Adler32 et CRC32. La première est la plus rapide.

Exemple :

// création d'un flux d'écriture sur fichier
FileOutputStream dest= new FileOutputStream("archive.zip");
// ajout du checksum : Adler32 (plus rapide) ou CRC32
CheckedOutputStream checksum = new CheckedOutputStream(dest, new Adler32());
// création d'un buffer d'écriture
BufferedOutputStream buff = newBufferedOutputStream(checksum);
// création d'un flux d'écriture Zip
ZipOutputStream out = new ZipOutputStream(buff);

XII - Accents

Malheureusement, les accents et caractères spéciaux sont mal interprétés par l'API java.util.zip, il faut donc transformer les noms qui en contiennent.

Exemple d'une fonction effectuant la conversion :

import sun.text.Normalizer;
public static String unAccent(String s) {
String temp = Normalizer.normalize(s, Normalizer.DECOMP, 0);
return temp.replaceAll("[^\\p{ASCII}]","");
}

Que l'on ajoute ici :

ZipEntry entry = new ZipEntry(unAccent(files[i]));

XIII - Méthode rapide : ZipFile

Il existe un moyen d'accéder rapidement aux entrées d'une archive :

ZipFile zipfile = newZipFile("archive.zip");
Enumeration entries = zipfile.entries();
while (entries.hasMoreElements()) {
ZipEntry e = ((ZipEntry)entries.nextElement());
System.out.println(e.getName());
}
zipfile.close();

Voici la liste des méthodes de la classe ZipFile :

Méthode

Description

ZipFile(String name)

Ouvre l'archive Zip

void close()

Ferme l'archive Zip

Enumeration entries()

Retourne l'ensemble des entrées

void finalize()

Fermeture de l'archive, lorsqu'inactive

ZipEntry getEntry(String name)

Retourne l'entrée de nom spécifié

InputStream getInputStream(ZipEntry entry)

Retourne un flux d'entrée vers le fichier associé à l'entrée spécifiée

String getName()

Retourne le chemin de l'archive

int size()

Retourne le nombre d'entrées

XIV - Historique

20 juin 2004 : création du document (24 diapos).

Agissez sur la qualité de ce document en envoyant vos critiques et suggestions à l'auteur.

Pour toute question technique, se reporter au forum Java de Developpez.com.

Reproduction autorisée uniquement pour un usage non commercial.

XV - Note et remerciement du gabarisateur

Cet article a été mis au gabarit de developpez.com. Voici le lien vers le PDF d'origine : zip.pdf.

Le gabarisateur remercie Claude LELOUP pour sa correction orthographique.