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.