Penser en Java 2nde édition | - | Sommaire | Préface | Avant-propos | Chapitre : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | Annexe : A B C D | Tables des matières | - | Thinking in Java |
La librairie qui supporte le format Zip est bien plus vaste. Avec elle vous pouvez facilement stocker des fichiers multiples, et il y a même une classe séparée pour amener le procédé de lecture d'un fichier Zip simple. La librairie utilise le format Zip standard de manière à ce qu'il fonctionne avec tous les outils couramment téléchargeables sur l'Internet. L'exemple suivant prend la même forme que l'exemple précédent, mais il manipule autant d'arguments de ligne de commande que vous le désirez. En plus, il met en valeur l'emploi de la classe Checksum pour calculer et vérifier la somme de contrôle [checksum] pour le fichier. Il y a deux sortes de Checksum : Adler32 (qui est rapide) et CRC32 (qui est plus lent mais légèrement plus précis).
Pour chaque fichier à ajouter à l'archive, vous devez appeler putNextEntry() et lui passer un objet ZipEntry. L'objet ZipEntry contient une interface extensible qui vous permet d'obtenir et de positionner toutes les données disponibles sur cette entrée précise dans votre fichier Zip : nom, tailles compressé et non-compressé, date, somme de contrôle CRC, données supplémentaires, commentaire, méthode de compression, et si il s'agit d'une entrée de répertoire. Toutefois, même si le format Zip possède une méthode pour établir un mot de passe, il n'est pas supporté dans la librairie Zip de Java. Et bien que CheckedInputStream et CheckedOutputStream supportent les deux contrôles de somme Adler32 et CRC32, la classe ZipEntry supporte seulement une interface pour la CRC (Contrôle de Redondance Cyclique). C'est une restriction sous-jacente du format Zip, mais elle pourrait vous limiter d'utiliser l'Adler32 plus rapide.
Pour extraire les fichiers, ZipInputStream a une méthode getNextEntry() qui renvoie la ZipEntry suivante si il y en a une. Comme alternative plus succincte, vous pouvez lire le fichier en utilisant un objet ZipFile, lequel possède une méthode entries() pour renvoyer une Enumeration auZipEntries.
Afin de lire la somme de contrôle vous devrez d'une manière ou d'une autre avoir accès à l'objet Checksum associé. Ici, une référence vers les objets CheckedOutputStream et CheckedInputStream est retenue, mais vous pourriez aussi juste vous en tenir à une référence à l'objet Checksum.
Une méthode déconcertante dans les flux de Zip est setComment(). Comme montré plus haut, vous pouvez établir un commentaire lorsque vous écrivez un fichier, mais il n'y a pas de manière pour récupérer le commentaire dans le ZipInputStream. Les commentaires sont apparemment complètement supportés sur une base d'entrée-par-entrée par l'intermédiaire de ZipEntry.
Bien sûr, vous n'êtes pas limité aux fichiers lorsque vous utilisez les librairies GZIP et Zip — vous pouvez compresser n'importe quoi, y compris les données a envoyer en passant par une connexion réseau.
Le format Zip est aussi employé dans le format de fichier JAR (Java ARchive), qui est une manière de rassembler un groupe de fichiers dans un seul fichier compressé, tout à fait comme Zip. Cependant, comme tout le reste en Java, les fichiers JAR sont multi-plate-forme donc vous n'avez pas a vous soucier des distributions de plate-forme. Vous pouvez aussi inclure des fichiers audio et image en plus des fichiers class.
Les fichiers JAR sont particulièrement utile quand on a affaire à l'Internet. Avant les fichiers JAR, votre navigateur Web devait faire des requêtes répétées sur un serveur Web afin de télécharger tous les fichiers qui composaient une applet. En plus, chacun de ces fichiers n'était pas compressé. En combinant tous les fichiers d'une applet précise dans un seul fichier JAR, une seule requête au serveur est nécessaire et le transfert est plus rapide en raison de la compression. Et chaque entrée dans un fichier JAR peut être signée digitalement pour la sécurité (se référer à la documentation de Java pour les détails).
Un JAR consiste en un seul fichier contenant une collection de fichiers zippés ensemble avec un « manifeste » qui en fait la description. (Vous pouvez créer votre propre fichier manifeste; sinon le programme jar le fera pour vous.) Vous pouvez trouver plus de précisions sur les manifestes dans la documentation HTML du JDK.
L'utilitaire jar qui est fourni avec le JDK de Sun compresse automatiquement les fichiers de votre choix. Vous lui faites appel en ligne de commande :
Les options sont simplement une collection de lettres (aucun trait d'union ou autre indicateur n'est nécessaire). Les utilisateurs noterons la similitude avec les options tar. Celles-ci sont :
c | Crée une archive nouvelle ou vide. |
t | Établit la table des matières. |
x | Extrait tous les fichiers. |
x file | Extrait le fichier nommé. |
f | Dit : « Je vais vous donner le nom du fichier. » Si vous n'utilisez pas ceci, jar considère que sont entrée viendra de l'entrée standard, ou , si il crée un fichier, sa sortie ira vers la sortie standard. |
m | Dit que le premier argument sera le nom du fichier manifeste crée par l'utilisateur. |
v | Génère une sortie « verbose » décrivant ce que jar effectue. |
0 | Stocke seulement les fichiers; ne compresse pas les fichiers (utilisé pour créer un fichier JAR que l'on peut mettre dans le classpath). |
M | Ne crée pas automatiquement un fichier manifeste. |
Si un sous-répertoire est inclus dans les fichiers devant être placés dans le fichier JAR, ce sous-répertoire est ajouté automatiquement, incluant tous ces sous-répertoire, etc. Les informations de chemin sont ainsi préservées.
Voici quelques façon typiques d'invoquer jar :
Ceci crée un fichier JAR appelé myJarFile.jar qui contient tous les fichiers class du répertoire courant, avec la génération automatique d'un fichier manifeste.
Comme l'exemple précèdent, mais ajoute un fichier manifeste crée par l'utilisateur nommé myManifestFile.mf.
Produit une table des matières des fichiers dans myJarFile.jar.
Ajoute le drapeau « verbose » pour donner des informations plus détaillées sur les fichiers dans myJarFile.jar.
Supposant que audio, classes, et image sont des sous-répertoires, ceci combine tous les sous-répertoires dans le fichier myApp.jar. Le drapeau « verbose » est aussi inclus pour donner contrôle d'information supplémentaire pendant que le programme jar travaille.
Si vous créez un fichier JAR en utilisant l'option o, ce fichier pourra être placé dans votre CLASSPATH :
Ainsi Java pourra chercher dans lib1.jar et lib2pour trouver des fichiers class.
L'outil jar n'est pas aussi utile que l'utilitaire zip. Par exemple, vous ne pouvez ajouter ou mettre à jour un fichier JAR existant; vous pouvez créer des fichiers JAR seulement à partir de zéro. Aussi, vous ne pouvez déplacer les fichiers dans un fichier JAR, les effaçant dès qu'ils sont déplacés. Cependant un fichier JAR crée sur une plate-forme sera lisible de manière transparente par l'outil jar sur n'importe quelle autre plate-forme (un problème qui apparaît parfois avec l'utilitaire zip.
Comme vous le verrez dans le chapitre 13, les fichiers JAR sont aussi utilisés pour emballer les JavaBeans.
La sérialisation objet en Java vous permet de prendre n'importe quel objet qui implémente l'interface Serializable et le dévie en une séquence de bytes qui pourront ensuite être complètement restaurés pour régénérer l'objet original. C'est même vrai à travers un réseau, ce qui signifie que le mécanisme de sérialisation compense automatiquement des différences dans les systèmes d'exploitation. C'est à dire, vous pouvez créer un objet sur un machine Windows, le sérialiser, et l'envoyer à travers le réseau sur une machine Unix où il sera correctement reconstruit. Vous n'avez pas à vous soucier de la représentation des données sur les différentes machines, l'ordonnancement des bytes, ou tout autres détails.
Par elle-même, la sérialisation objet est intéressante parce qu'elle vous permet de mettre en application la persistance légère [lightweight persistence]. Rappelez-vous que la persistance signifie que la durée de vie de l'objet n'est pas déterminée tant qu'un programme s'exécute — l'objet vit dans l'intervalle des invocations du programme. En prenant un objet sérialisable et en l'écrivant sur le disque, puis en ressortant cet objet lors de la remise en route du programme, vous êtes alors capable de produire l'effet de persistance. La raison pour laquelle elle est appelée « légère » est que vous pouvez simplement définir un objet en employant un certain type de mot-clé pour la « persistance » et de laisser le système prendre soin des détails (bien que cela peut bien arriver dans le futur). À la place de cela, vous devrez sérialiser et désérialiser explicitement les objets dans votre programme.
La sérialisation objet a été ajoutée au langage pour soutenir deux caractéristiques majeures. La remote method invocation (RMI) de Java permet aux objets qui vivent sur d'autres machines de se comporter comme si ils vivaient sur votre machine. Lors de l'envoi de messages aux objets éloignés, la sérialisation d'objet est nécessaire pour transporter les arguments et les valeurs retournées. RMI est abordé au Chapitre 15.
La sérialisation des objets est aussi nécessaire pour les JavaBeans, décrit au Chapitre 13. Quand un Bean est utilisé, son information d'état est généralement configuré au moment de la conception. Cette information d'état doit être stockée et récupérée ultérieurement quand le programme est démarré; la sérialisation objet accomplit cette tâche.
Sérialiser un objet est assez simple, aussi longtemps que l'objet implémente l'interface Serializable (cette interface est juste un drapeau et n'a pas de méthode). Quand la sérialisation est ajoutée au langage, de nombreuses classes sont changés pour les rendre sérialisables, y compris tous les envelloppeurs [wrappers] pour les types de primitives, toutes les classes de récipients [container], et bien d'autres. Même les objets Class peuvent être sérialisés. (Voir le Chapitre 12 pour ce que cela implique.)
Pour sérialiser un objet, vous créez une sorte d'objet OutputStream et l'enveloppez ensuite dans un objet ObjectOutputStream. À ce point vous avez seulement besoin d'appeler writeObject() et votre objet est sérialisé et envoyé à l'OutputStream. Pour inverser le processus, vous enveloppez un InputStream dans un ObjectInputStream et appelez readObject(). Ce qui renvoie, comme d'habitude, une référence à un Objet dont on a sur-forcé le type [upcast], ainsi vous devrez sous-forcer pour préparer les objets directement.
Un aspect particulièrement astucieux de la sérialisation objet est qu'elle ne sauve pas uniquement une image de votre objet, mais cela s'occupe aussi de toutes les références contenues dans votre objet et sauve ces objets, et poursuit dans toutes les références de ces objets, etc. Ceci est parfois rapporté comme le « Web des objets » auquel un simple objet peut être connecté, et il comprend des tableaux de références aux objets aussi bien que d'objets membres. Si vous devez entretenir votre propre schéma de sérialisation, entretenir le code pour suivre tous ces liens serait un peu un casse-tête. Pourtant, la sérialisation d'objet Java semble s'en sortir sans faute, sans aucun doute en utilisant un algorithme optimalisé qui traverse le Web des objets. L'exemple suivant teste le mécanisme de sérialisation en créant un « vers » d'objets liés, chacun d'entre eux ayant un lien jusqu'au prochain segment dans le vers en plus d'un tableau de références aux objets d'une classe différent, Data :