Fichiers, flots et entrées/sorties paquetage java.io
Les fichiers, classe File Cette classe représente un «chemin abstrait vers un fichier» ; le terme «abstrait» signifie indépendant du système d exploitation ; cette classe permet de manipuler les fichiers de la même manière, quelle que soit le système d exploitation ; représente aussi bien les fichiers que les répertoires.
Les fichiers, class File L existence de fichier ou la correction du chemin n est pas vérifié lors de la création ; la validité du chemin est testée soit par des des méthodes de File, soit quand on essaye de lire dans le fichier construire un objet File avec un chemin complet nécessite de mettre ce chemin suivant la syntaxe du système à ne pas faire utiliser Class(Loader).getResource() utiliser JFileChooser demande le fichier en ligne de commande
Les fichiers, classe File Permet de tester les métadonnées du fichier : length, canwrite, canread, exists, isdirectory, isfile permet d obtenir la représentation du fichier : getcanonicalpath, getparent, getname, getabsolutefile
Les fichiers, classe File Permet de créer, renommer et supprimer des fichiers ou répertoires : createnewfile, mkdir, mkdirs, renameto, setlastmodified on peut dire à la machine virtuelle de supprimer le fichier à sa terminaison normale avec deleteonexit ; on peut créer un fichier temporaire avec createtempfile.
Les fichiers, classe File On peut lister les fichiers d un répertoire avec la méthode listfiles ou list ; on peut peut ne lister que les fichiers correspondant à un certain critère en donnant un objet implémentant l interface FileFilter ou l interface FilenameFilter comme argument à ces méthodes.
Exemple // Affiche tous les fichiers.java de /var/tmp File temp = new File("/var/tmp"); FilenameFilter filter = new FilenameFilter() { public boolean accept(file f,string name) { return name.endswith(".java"); } }; String[] sources = temp.listfiles(filter); System.out.println(Arrays.asList(sources));
Les flots ou flux Un flot est une suite d «éléments», les uns à la suite des autres ; un flot en entrée permet de lire des éléments ; un flot en sortie permet d écrire des éléments.
Il y a deux grandes classes de flots : Les flots en java les flots d éléments binaires, sous-classes de InputStream et OutputStream ; les flots de caractères unicode, sous-classes de Reader et Writer ; dans chaque famille, il y a des flots concrets, et des filtres ; les filtres sont des flots ajoutant des fonctionnalités à d autres flots.
InputStream (binaire) Cette classe est la classe abstraite parente de tous les flots binaires en entrée ; elle contient des méthodes de lecture read : bloquantes ; lisent au plus le nombre d octets demandés ; renvoient le nombre d octets lus (à tester!!!) ou l octet lu pour read() ; renvoient -1 en fin de flot lèvent IOException en cas d erreur.
Exemple byte[] buffer // des bytes car flot binaire buffer = new byte[100]; // demande au plus 100 octets int ans = System.in.read(buffer); if (ans == -1) // fin de fichier return; /* demande ce qu il manque pour faire 100, en le stockant à partir de ans */ System.in.read(buffer,ans,100-ans); // on est toujours pas sur d'avoir lu 100 octets
InputStream La méthode close permet de fermer un flux (et comme en système de finaliser l'écriture et libérer la ressource) ; la méthode available renvoie le nombre d octets disponibles i.e. read non bloquant pour ce nombre d octets (bref une information non fiable) ; les méthodes mark et reset permettent de marquer le flux à la position courante pour y retourner, skip de sauter des octets ; la méthode marksupported indique si ce mécanisme est implémenté.
Reader (caractères) Cette classe est la classe abstraite parente de tous les flots de caractères en entrée ; elle contient des méthodes de lecture read : bloquantes ; lisent au plus le nombre de caractères demandés ; renvoient le nombre de caractères lus ( ) ou le caractère lu pour read() ; renvoient -1 en fin de flot lève IOException en cas d erreur.
Reader La méthode close permet de fermer un flux ; la méthode ready indique si au moins un caractère est disponible (idem non fiable) ; les méthodes mark et reset permettent de marquer le flux à la position courante pour y retourner, skip de sauter des caractères ; la méthode marksupported indique si ce mécanisme est implémenté.
OutputStream/Writer Ces classes sont les classes abstraites parentes de tous les flots d octets ou caractères en sortie ; elle contient des méthodes de lecture write : bloquantes ; écrivent exactement le nombre de caractères demandés ; renvoient void ; les Writer peuvent écrire des String lèvent IOException en cas d erreur ; close permet de fermer le flot ; flush de vider les caches.
Exemple byte[] buffer = new byte[] {1,2,3,4}; // écrit 0 System.out.write(0); // écrit 1 2 3 4 System.out.write(buffer); // écrit 2 3 System.out.write(buffer,1,2); // vide les caches System.out.flush(); char[] buffer = new char[] { a, b, c, d }; Writer writer = // écrit r writer.write( r ); // écrit abcd writer.write(buffer); // écrit Hello writer.write("hello"); // ferme le flot writer.close();
Flots d'un fichier Les classes FileReader, FileWriter, FileInputStream et FileOutputStream permettent de lire et écrire dans un fichier ; pour les FileReader et FileWriter, le codage des caractères choisi est le codage par défaut du système
Flots d'un tableau Les classes CharArrayReader, StringReader et ByteArrayInputStream permettent de voir un tableau ou une chaîne comme un flot (supportant mark) Les classes CharArrayWriter, StringWriter et ByteArrayOutputStream permettent d'écrire dans un tableau avec un mécanisme de flux ; la taille du tableau est augmentée quand nécessaire ;
Flots d une chaîne On récupère le tableau avec tochararray ou tobytearray. Pour CharArrayWriter et StringWriter, la méthode tostring renvoie la chaîne correspondante à ce qui a été écrit ; pour StringWriter, la méthode getbuffer retourne l objet StringBuffer associé.
Tubes Les classes PipedInputStream/OS, PipedReader/Writer permettent d avoir des flux «tubes» : un tube en entrée est connecté à un tube en sortie de même type (octets ou caractères) ; les données écrites dans l entrée du tube (Writer ou OutputStream) peuvent être lues dans la sortie du tube (Reader ou InputStream).
Tubes Les tubes peuvent être utilisés comme moyen de communication entre Thread (processus légers) ; il est déconseillé de les utiliser dans un même Thread (risque de blocage). quand l un des Thread communiquant meurt, la lecture ou l écriture sur l autre côté du tube provoque une IOException. on préférera utiliser les collections bloquantes
Filtres En plus des flots concrets, il existe des flots appelés «filtres», qui ajoutent des fonctionnalités aux flots existants ; ces flots ont un constructeur prenant un flot qui sera utilisé pour les opérations d écriture «bas niveau», et fournissent des opérations d écritures «haut niveau» (comme par exemple printf par rapport à write).
Codage de caractères Les classes InputStreamReader et OutputStreamWriter permettent de transformer un flot d'octets en flot de caractères ; soit on spécifie un codage de caractères ; soit est pris celui par défaut du système, éventuellement différent pour chaque système ; quand on écrit un protocole réseau, il faut choisir un codage de caractères.
Codage de caractères On spécifie un codage par son nom, un objet Charset ou un objet CharsetDecoder du paquetage java.nio.charset ; les codages disponibles sont donnés par java.nio.charset.charset.availablecharsets() ; tous les flots qui transforment mal des octets en caractères sont dépréciés (comme StringBufferInputStream) on peut aussi utiliser les nio!
Flots bufferisés Les classes BufferedInputStream/OS BufferedReader/Writer ajoutent une bufferisation au flot ; cela permet de lire ou écrire caractère par caractère de manière efficace ; la classe BufferedReader permet de lire ligne par ligne avec la méthode readline ;
Numéro de ligne La classe LineNumberReader maintient en plus un numéro de ligne (la méthode setlinenumber ne change pas la position dans le flot) ; la classe LineNumberInputStream est dépréciée car n a pas de gestion correcte des codages de caractères.
Flots d affichage La classe PrintWriter permet d afficher la représentation de n importe quelle valeur, de type primitif ou objet avec les méthodes print ou println ; la méthode println ajoute un retour-chariot à la fin mais pas print ; pour les objets, la méthode tostring est appelée.
Flots d affichage La classe PrintStream effectue la même chose que la classe PrintWriter, soit en convertissant avec le codage par défaut, soit en utilisant celui donné à la construction ; la méthode println ajoute un retour-chariot à la fin mais pas print ; pour les objets, la méthode tostring est appelée.
Flots d affichage Les méthodes de la classe PrintWriter et PrintStream ne lancent pas IOException ; on utilise checkerror pour savoir s'il y a eu une erreur (on ne peut pas savoir laquelle) ; par défaut, les données ne sont pas «flushed» automatiquement ; avec l argument de constructeur autoflush à true, une écriture d un buffer ou d un \n provoque le flush du flot.
Flots d'affichage Les deux classes disposent d'une méthode printf (merci l'autoboxing et le variadique) Ce service est délégué à la classe java.util.formatter sprintf est la méthode String.format le format est similaire (mais bien plus riche...) à celui de la libc, avec %n pour le retour chariot (dépendant de la plateforme)
Flots «Pushback» Les flots PushbackInputStream et PushbackReader permettent de remettre des caractères ou octets, lus ou non, dans le flot pour les lire à nouveau ; on remet des caractères avec unread ; ceci est réalisé avec un buffer fini, dont la méthode unread lance un IOException quand le buffer est plein ; on ne s'en sert pas souvent, et en plus la doc est fausse...
Flot séquentiel La classe SequenceInputStream prend un ensemble d'inputstream, et émule la concaténation de ces flots : il retourne d'abord les octets du premier jusqu'à la fin ; puis les octets des flots suivants, jusqu'à arriver à la fin du dernier flot.
Flots de données Les flots DataInputStream et DataOutputStream servent à écrire ou lire des données d une manière indépendante du système ; l'exception EOFException est lancée à la fin du flot ; la méthode readfully permet de bloquer jusqu à ce que soient lues le nombre d octets demandés les spécifications des méthodes sont données par les interfaces DataInput et DataOutput
Exemple public void writenamedpoint(dataoutputstream out, NamedPoint p) throws IOException { out.writeint(p.x); out.writeint(p.y); out.writeutf(p.name); } public NamedPoint readnamedpoint (DataOutputStream in) throws IOException { int x = in.readint(); int y = in.readint(); String name = in.readutf(); return new NamedPoint(name,x,y); }
Accès aux fichiers On peut lire et écrire dans un fichier avec la classe RandomAccessFile ; On peut spécifier différents modes : "r" lecture seule ; "rw" lecture et écriture, avec création du fichier ; "rwd" comme "rw", mais synchronisé avec le système de fichiers (sauf réseau) ; "rws" comme "rwd", mais les statistiques du fichier sont aussi synchronisées
Accès aux fichiers On se déplace dans le fichier avec la méthode seek ; on accède à la position courante avec getfilepointer ; on obtient la longueur avec length, que l'on change avec setlength ; on le ferme avec close ; On peut écrire et lire des données comme dans DataInputStream et DataOutputStream ; on ne peut pas spécifier de codage de caractères les spécifications des méthodes sont données par les interfaces DataInput et DataOutput
Flots d objets Les flots ObjectInputStream et ObjectOutputStream permettent de stocker et restaurer des objets ; EOFException est lancée à la fin du flot ; le système inclus un système de version de classe ; les objets écrits dans les flots doivent implémenter l interface marqueur Serializable ; bien sûr, Object n est pas sérialisable.
Flots d objets Lors du stockage d un objet, la machine virtuelle recherche tous les objets dépendants et les stocke aussi, en repérant les boucles ; seuls les attributs de la classe et des superclasses sérialisables sont stockés dans le flot, sauf s ils sont marqués transient ; ces attributs doivent être eux-mêmes sérialisable ou l exception NotSerializableException est levée.
Flots d objets Lors de la restauration d un objet, l'initialisation des champs se fait comme avec un constructeur : de Object à la classe ; le constructeurs sans paramètres de la première superclasse non sérialisable est appelé, et leurs champs sont initialisés par ce dernier, et ne reprennent donc pas leur ancienne valeur ; l exception InvalidClassException est levée s il n existe pas ; les champs non transient des superclasses sérialisables et de la classe sont restaurés, sans appel à un constructeur, les autres initialisés à leur valeur par défaut (0, null, false)
public class A { int x,y; public A() { this(3,3); } public A(int x,int y) { this.x=x; this.y=y; } } public class B extends A implements Serializable { transient int z = 8; int a; } B b = new B(); b.x=10;b.y=11;b.z=12;b.a=13; out.writeobject(b); out.close(); Exemple B b = (B)in.readObject(); System.out.printf("x=%d y=%d z=%d a=%d%n",b.x,b.y,b.z,b.a); in.close(); x=3 y=3 z=0 a=13
Flots d objets La sérialisation permet aussi de transmettre des objets via le réseau, ou à une autre application java (drag and drop, copier/coller) On peut ajouter des méthodes éventuellement privées à une classe, readobject(objectinputstream) et writeobject(objectoutputstream) pour mieux contrôler la sauvegarde et la restauration Elle seront appelées à la place du mécanisme par défaut
Créations de nouveaux flots Les classes abstraites InputStream, OutputStream, Reader et Writer permettent de créer facilement de nouveaux flots ; les classes FilterInputStream, FilterOutputStream et les classes abstraites FilterReader et FilterWriter permettent de créer de nouveaux filtres.