Fichiers, flots et entrées/sorties paquetage java.io

Transcription

Fichiers, flots et entrées/sorties paquetage java.io
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.
Les flots en java
●
Il y a deux grandes classes de flots :
–
–
●
●
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)
Exemple
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();
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.