LES ENTREÉS/SORTIES
Les entrées/sorties
• Introduction
• Grandes catégories de flux
• Flux physiques / Flux logiques
• Compositions des flux
• Gestion des exceptions / fermeture
• Flux d’entrées/sorties standards
• Flux de données / Flux d’objets
• Fichiers à accès direct
Entrées/Sorties en Java
➔package java.io
➔ vision unifiée de toutes les opérations d'entrées/sorties sous forme de flux séquentiels (Stream)
Flux (Stream) : élément dans lequel on pourra effectuer
➔des opérations de lecture séquentielles : flux d'entrée
➔des opérations d’écriture séquentielles : flux de sortie Intérêt : uniformité
➔on utilise les mêmes opérations, pour lire/écrire
➔dans un fichier,
➔dans entrées/sorties standards,
➔via le réseau
➔etc…
Inconvénient : au départ ça paraît un peu compliqué…
Introduction
4 grandes catégories de flux :
Les 4 grandes catégories de flux
Flux d'octets Flux de caractères Flux d'entrée InputStream Reader
Flux de sortie OutputStream Writer
Pour chaque catégorie d'éléments qu'on peut utiliser en entrée/sortie, on aura une sous classe…
Les sous-catégories de flux
fichier
flux d'objets
types primitifs
concaténation de flux
flux
bufférisé
Pour chaque catégorie d'éléments qu'on peut utiliser en entrée/sortie, on aura une sous classe…
Les sous-catégories de flux
fichier
flux d'objets
types primitifs
flux
bufférisé
Pour chaque catégorie d'éléments qu'on peut utiliser en entrée/sortie, on aura une sous classe…
Les sous-catégories de flux
fichier numérotation des lignes
Chaîne de caractères transformation
d'un flux d'octets
en flux de caractères
Pour chaque catégorie d'éléments qu'on peut utiliser en entrée/sortie, on aura une sous classe…
Les sous-catégories de flux
avec un buffer
Fichier
Chaîne de caractères
Flux physiques
• Les classes InputStream/OutputStream/Reader/Writer définissent les méthodes de base:
– lecture / écriture d’octets / de caractères
• Elles sont déclinées pour différents types de supports
– Fichiers
➔ FileInputStream/FileOutputStream
➔ FileReader/FileWriter – Tableaux
➔ ByteArrayInputStream/ByteArrayOutputStream
➔ CharArrayInputStream/CharArrayOutputStream – String
➔ StringReader/StringWriter
Flux logiques
• D’autres classes permettent de transformer des flux
– Transformation de flux d’octets en flux de caractères
• InputStreamReader/OutputStreamWriter
• Ou leur ajouter des fonctionnalités
– Ajout d’un buffer
• BufferedInputStream/BufferedOutputStream
• BufferedReader/BufferedWriter
– Ajout de méthodes print
• PrintStream/ PrintWriter
– Lecture écriture d’objets binaires
• DataInputStream/DataOutputStream (types primitifs)
• ObjectInputStream/ObjectOutputStream (objets java)
– Compression/Décompression
• DeflaterInputStream/DeflaterOutputSream (compression)
• InflaterInputStream/InflaterOutputSream (decompression)
– Etc.
Il existe des sous-classes pour différents formats :
GZip : GZIPInputStream GZIPOutputStream Zip : ZipInputStream
ZipOutputStream Jar : JarInputStream
JarOutputStream
Exemple écriture dans un fichier
Écriture de caractères dans un fichier :
…
// obtention flux de sortie binaire
OutputStream fos = new FileOutputStream("C:/temp/test.txt");
// transformation en flux de charactères
Writer fWriter = new OutputStreamWriter(fos, "UTF-8");
// Ajout d’un buffer
Writer buffWriter = new BufferedWriter(fWriter);
// transformation en PrintWriter
PrintWriter pOut = new PrintWriter(buffWriter);
// Ecriture dans le fichier avec les méthodes print pOut.println("Hello World!");
pOut.println(Math.PI * 3.0);
…
// fermeture des flux (une fois qu’on n’en a plus besoin) pOut.close();
Remarque : si on ne précise pas l’encodage, l’encodage par défaut de la vm java est utilisé
Exemple écriture dans un fichier
• On part d’un flot basique (FileOutputStream) et
• On l’encapsule dans un ou plusieurs flux pour
• le transformer ou
• ajouter des nouvelles fonctionnalités
new PrintWriter(
new BuffererdWriter(
new OutputStreamWriter(
new FileOutputStream("C:/temp/test.txt")
"UTF-8")))
FileOutputStream OutputStreamWriter
BufferedWriter
PrintWriter
Exemple écriture dans une chaîne de caractères
Écriture dans une chaîne de caractères :
…
// obtention flux de sortie de type caractères Writer sWriter = new StringWriter();
// Ajout d’un buffer
Writer buffWriter = new BufferedWriter(sWriter);
// transformation en PrintWriter
PrintWriter pOut = new PrintWriter(buffWriter);
// Ecriture dans le fichier avec les méthodes print pOut.println("Hello World!");
pOut.println(Math.PI * 3.0);
…
// fermeture des flux (une fois qu’on n’en a plus besoin) pOut.close();
// Récupération de la chaine de caractères
String s = sWriter.toString();
Exemple écriture dans une chaîne de caractères
• On part d’un flot basique (StringWriter) et
• On l’encapsule dans un ou plusieurs flux pour
• le transformer ou
• ajouter des nouvelles fonctionnalités
new PrintWriter(
new BuffererdWriter(
new StringWriter() ) )
StringWriter BufferedWriter
PrintWriter
Méthodes importantes
Méthodes pour java.io.InputStream :
• void close() fermeture du flux.
• int available() nombre d'octets disponibles sur le flux.
Lecture
• abstract int read() lecture d'un octet.
• int read(byte[ ] b) utilisation d'un tableau d'octets comme buffer.
• int read(byte[ ] b, int off, int len) idem.
Déplacement
• long skip(long n) on saute n octets.
Repositionnement
• boolean markSupported() si les méthodes mark et reset sont utilisables.
• void mark(int readlimit) mémorisation de la position actuelle.
• void reset() on revient à la position mémorisée avec mark.
Méthodes importantes
Méthodes pour java.io.Reader :
• void close() fermeture du flux.
• boolean ready() indique si le flux est prêt pour une lecture.
Lecture
• abstract int read() lecture d'un caractère.
• int read(char[ ] cbuf) utilisation d'un tableau de caractères comme buffer.
• int read(char[ ] cbuf, int off, int len) idem.
Déplacement
• long skip(long n) on saute n caractères.
Repositionnement
• boolean markSupported() si les méthodes mark et reset sont utilisables.
• void mark(int readlimit) mémorisation de la position actuelle.
• void reset() on revient à la position mémorisée avec mark.
Méthodes importantes
Méthodes pour java.io.OutputStream :
• void close() fermeture du flux.
• boolean flush() force l'écriture des octets (utile si il y a un buffer).
Écriture
• abstract void write(int b) écriture d'un octet.
• void write(byte[ ] b) utilisation d'un tableau d'octets.
• void write(byte[ ] b, int off, int len) idem.
Méthodes pour java.io.Writer :
• void close() fermeture du flux.
• boolean flush() force l'écriture des caractères (utile si il y a un buffer).
Écriture
• abstract void write(int b) écriture d'un caractère.
• void write(char[ ] cbuf) utilisation d'un tableau de caractères.
• void write(char[ ] cbuf, int off, int len) idem.
• void write(String str) utilisation d'une chaîne de caractères.
• void write(String str, int off, int len) idem.
Méthodes importantes
Méthodes pour java.io.PrintStream et java.io.PrintWriter :
• PrintStream(OutputStream out)
• PrintStream(OutputStream out, boolean autoFlush, String encoding)
• PrintWriter(OutputStream out)
• PrintWriter(OutputStream out, boolean autoFlush)
• PrintWriter(Writer out)
• PrintWriter(Writer out, boolean autoFlush) Écriture
• void print(boolean b)
• void println(boolean b)
• void print(char c)
• void println (char c)
• …
• void print(String s)
• void println(String s)
• void print(Object obj)
• void println (Object obj)
Méthodes importantes
Méthodes pour BufferedReader et BufferedWriter :
java.io.BufferedReader
• BufferedReader(Reader in)
• BufferedReader(Reader in, int sz)
• String readLine() Read a line of text.
java.io.BufferedWriter
• BufferedWriter(Writer out)
• BufferedWriter(Writer out, int sz)
• void newLine() Write a line separator.
Fermeture des flux Gestion des exceptions
• Fermeture des flux :
– Une fois qu’on a fini d’utiliser un flux, il faut le fermer
• méthode close()
– Les plupart des méthodes de lecture/écriture peuvent générer des exceptions ( java.io.IOException )
• On va les capturer avec
➔ try catch
➔ try-with-resources catch
Fermeture des flux Gestion des exceptions
• Exemple avec try catch :
InputStream in = new FileInputStream("C:/temp/test.ppt");
OutputStream out = new FileOutputStream("C:/temp/test2.ppt");
try {
int b = in.read();
while (b != -1) { out.write(b);
b = in.read();
}
}
catch
(IOException e) {System.err.println("erreur sur le flux");
} finally { in.close();
out.close();
}
Peut générer des exceptions
Peut générer des exceptions
Peut générer des exceptions
Les flux doivent être fermés quand on n’en a plus besoin
Problème : la fermeture des flux peut aussi générer des exceptions
Fermeture des flux Gestion des exceptions
• Exemple avec try-with-resources catch :
try (
InputStream in = new FileInputStream("C:/temp/test.ppt");
OutputStream out = new FileOutputStream("C:/temp/test2.ppt") ){
int b = in.read();
while (b != -1) { out.write(b);
b = in.read();
}
}
catch
(IOException e) {System.err.println("erreur sur le flux");
}
• Les ressources définies dans le try-with-resources sont automatiquement fermées à la fin du try catch
Peut générer des exceptions
Peut générer des exceptions
Peut générer des exceptions
Les flux sont automatiquement fermés à la fin du try catch
Les Entrées/Sorties standards
La classe System permet d'accéder aux 3 flux standards :
– System.in ➔ flux d'entrée "standard" (par défaut → clavier)
– System.out ➔ flux de sortie "standard" (par défaut → console écran) – System.err ➔ flux d'erreur "standard" (par défaut → console écran)
Types de flux associés aux flux standards :
– System.in → java.io.InputStream – System.out → java.io.PrintStream – System.err → java.io.PrintStream
Changement des flux standards :
– System.setIn (InputStream in )
– System.setOut (PrintStream out )
– System.setErr (PrintStream err )
Exemple
Écriture sur le flux de sortie Standard :
…
System.out.println("Bonjour, ");
System.out.print("écriture d'un réel (PI): ");
double pi = Math.PI;
System.out.println(pi);
…
Lecture d'un entier sur le flux d'entrée Standard :
…
InputStreamReader in0 = new InputStreamReader(System.in);
BufferedReader in1 = new BufferedReader(in0);
try {
String s = in1.readLine();
int k = Integer.parseInt(s);
} catch (IOException e) {
System.err.println("erreur de lecture sur le flux");
} catch (NumberFormatException e) {
System.err.println("erreur de conversion de l'entier");
}
Exemple
Copie d'un fichier :
…
InputStream in = new FileInputStream("C:/temp/test.ppt");
OutputStream out = new FileOutputStream("C:/temp/test2.ppt");
try {
int b = in.read();
while (b != -1) { out.write(b);
b = in.read();
}
} catch (IOException e) {
System.err.println("erreur sur le flux");
} finally { in.close();
out.close();
}
…
Exemple : avec un pipe
Coté producteur :
public class Producteur implements Runnable { private PipedWriter out;
public Producteur(PipedWriter out) { this.out = out;
}
public void run(){
try {
out.write("Hello\n");
out.write("World\n");
} catch (IOException e) {
System.err.println("erreur d'écriture");
} finally { out.close();
} } }
Exemple : avec un pipe
Coté consommateur :
public class Consommateur implements Runnable { private PipedReader in;
public Consommateur(PipedReader in) { this.in = in;
}
public void run(){
try ( BufferedReader in = new BufferedReader(this.in)){
String s = in.readLine();
while (s != null) {
System.out.println("lecture de : "+ s );
s = in.readLine();
}
} catch (IOException e) {
System.err.println("erreur d'écriture");
} } }
Exemple : avec un pipe
Lancement des processus :
…
PipedReader in = new PipedReader();
PipedWriter out = new PipedWriter();
try {
out.connect(in);
Thread tProd = new Thread(new Producteur(out));
Thread tCons = new Thread(new Consommateur(in));
tProd.start();
Thread.sleep(10);
tCons.start();
}
catch(Exception e) {
…
}
…
Exemple : avec un pipe
Coté producteur :
public class Producteur implements Runnable { private Writer out;
public Producteur(Writer out) { this.out = out;
}
public void run(){
try {
out.write("Hello\n");
out.write("World\n");
} catch (IOException e) {
System.err.println("erreur d'écriture");
} finally { out.close();
} } }
Exemple : avec un pipe
Coté consommateur :
public class Consommateur implements Runnable { private BufferedReader in;
public Consommateur(Reader in) { this.in = new BufferedReader(in);
}
public void run(){
try {
while (in.ready()) {
String s = in.readLine();
System.out.println("lecture de : "+ s );
}
} catch (IOException e) {
System.err.println("erreur de lecture");
} finally { in.close();
} } }
Exemple : avec des sockets
Sur le serveur
//port d'écoute du listener
ServerSocket ssServer=new ServerSocket(8080);
Socket sSocket=null;
//on attend en attendant une connexion cliente while(sSocket==null){
sSocket=ssServer.accept();
}
Writer out = new OutputStreamWriter(sSocket.getOutputStream());
Thread tProd = new Thread(new Producteur(out));
tProd.start();
sur le client
// connection
Socket sSocket=new Socket("127.0.0.1",8080);
Reader in = new InputStreamReader(sSocket.getInputStream());
//creation et lancement du client
Thread tCons = new Thread(new Consommateur(in));
tCons.start();
On écrire/lire des entiers, réels,… sur des flux d'entrées/sorties
➔flux de sortie : java.io.DataOuputStream
➔flux d'entrée : java.io.DataInputStream
Écriture : pour chaque type primitif on aura une méthode spécifique
➔void writeBoolean(boolean b)
➔void writeInt(int i)
➔void writeDouble(double r)
➔…
Lecture : pour chaque type primitif on aura une méthode spécifique
➔boolean readBoolean( )
➔int readInt( )
➔double readDouble( )
➔…
Format utilisé : format binaire (pas utilisable pour les flux standards)
Flux de données primitives
Flux de données
Flux en écriture : java.io.DataOutputStream
Constructeur :
– DataOutputStream ( OutputStream in ) constructeur du flux.
Écriture de données de type primitif
– void writeBoolean(boolean b) écriture d'un booléen
– void writeByte(int b) écriture d'un octet
– void writeChar(int c) écriture d'un caractère
– void writeShort(int i)
– void writeInt(int i) écriture d'un entier
– void writeLong(long l)
– void writeFloat(float v) lecture d'un float
– void writeDouble(double v) lecture d'un double
– void writeUTF(String s) écriture d'une String au format UTF-8
Flux de données
Flux en lecture : java.io.DataInputStream
Constructeur :
– DataInputStream ( InputStream in ) constructeur du flux.
Lecture de données de type primitif
– boolean readBoolean() lecture d'un booléen
– byte readByte() lecture d'un octet
– char readChar() lecture d'un caractère
– short readShort()
– int readInt() lecture d'un entier
– int readUnsignedByte() – int readUnsignedShort() – long readLong()
– float readFloat() lecture d'un float
– double readDouble() lecture d'un double
– String readUTF() lecture d'un chaîne de caractère au format UTF-8
Exemple : flux de données
Sauvegarde de types primitifs :
…
OutputStream fos = new FileOutputStream("C:/temp/test.data");
DataOutputStream dos = new DataOutputStream(fos);
double[] tab = {1.0,2.0,3.0,4.0,5.0,6.0} ; try {
dos.writeBoolean(tab != null);
dos.writeInt (tab.length);
for (int i=0; i < tab.length ; i++){
dos.writeDouble(tab[i]);
}
}
catch(IOException e) {
System.err.println("erreur sur le flux");
} finally {
dos.close();
}
…
Exemple : flux de données
Récupération de types primitifs :
InputStream fis = new FileInputStream("C:/temp/test.data");
DataInputStream dis = new DataInputStream(fis);
double[] tab = null;
try {
// on regarde si le tableau n'était pas vide...
if (dis.readBoolean()) {
// on lit la taille du tableau int taille = dis.readInt();
tab = new double[taille];
for (int i=0; i < taille ; i++){
tab[i] = dis.readDouble();
} }
} catch (IOException e) {
System.err.println("erreur sur le flux");
} finally {
dis.close();
}
Exemple : avec des tableaux
Sauvegarde :
...
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bOut);
double[] tab = {1.0,2.0,3.0,4.0,5.0,6.0} ; try {
// on regarde si le tableau n'était pas vide...
if (dos.writeBoolean(tab != null)) { ...
Récupération
...
InputStream bIn = new ByteArrayInputStream(bOut.toByteArray());
DataInputStream dis = new DataInputStream(bIn);
double[] tab = null;
try {
// on regarde si le tableau n'était pas vide...
if (dis.readBoolean()) { ...
On peut utiliser les flux d'entrées/sorties pour sauver des objets java :
➔flux de sortie : java.io.ObjectOutputStream
➔flux d'entrée : java.io. ObjectInputStream
Écriture d'un objet : par défaut le système sauvegarde
➔la classe de l'objet et tous les attributs sauf
➔les attributs static (car ils sont sur la classe) et
➔les attributs transient
➔si un attribut contient un objet, cet objet est lui aussi sauvé !
Lecture d'un objet : comme l'écriture mais en sens inverse Contrainte :
➔l'objet doit être sérialisable : i.e. implanter java.io.serializable
➔tous les attributs à sauver doivent être
➔soit de type primitif (boolean, int, float, double, …)
➔soit sérialisables (et implanter aussi java.io.serializable)
Flux d'Objets
Flux d'Objets
Flux en écriture : java.io.ObjectOutputStream
Constructeur :
– ObjectOutputStream ( OutputStream in ) constructeur du flux.
Écriture
– void writeBoolean(boolean b) écriture d'un booléen
– void writeByte(int b) écriture d'un octet
– void writeChar(int c) écriture d'un caractère
– void writeShort(int i)
– void writeInt(int i) écriture d'un entier
– void writeLong(long l)
– void writeFloat(float v) lecture d'un float
– void writeDouble(double v) lecture d'un double
– void writeUTF(String s) écriture d'une String au format UTF-8
– void writeObject(Object obj) écriture d'un objet sérialisable
Flux d'Objets
Flux en lecture : java.io.ObjectInputStream
Constructeur :
– ObjectInputStream ( InputStream in ) constructeur du flux.
Lecture
– boolean readBoolean() lecture d'un booléen
– byte readByte() lecture d'un octet
– char readChar() lecture d'un caractère
– short readShort()
– int readInt() lecture d'un entier
– int readUnsignedByte() – int readUnsignedShort() – long readLong()
– float readFloat() lecture d'un float
– double readDouble() lecture d'un double
– String readUTF() lecture d'un chaîne de caractère au format UTF-8
– Object readObject() lecture d'un objet sérialisable
Exemple1 : flux d'objets
Sauvegarde des objets:
OutputStream fos = new FileOutputStream("C:/temp/test.obj");
ObjectOutputStream oos = new ObjectOutputStream(fos);
double[] tab = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0} ; try {
oos.writeObject(tab);
} catch (IOException e) {
System.err.println("erreur sur le flux");
} finally { oos.close(); }
Récupération des objets :
InputStream fis = new FileInputStream("C:/temp/test.obj");
ObjectInputStream ois = new ObjectInputStream(fis);
double[] tab = null;
try {
tab = (double[])ois.readObject();
} catch (IOException e) {
System.err.println("erreur sur le flux");
} catch (ClassNotFoundException e) {
System.err.println("Type d'objet inconnu");
} finally { ois.close(); }
Exemple2 : flux d'objets
Sauvegarde des objets : exemple classe Personne
public class Personne implements Serializable {
static private final long serialVersionUID = 6L;
private String nom;
private String adresse;
public Personne(String nom, String adresse){
this.nom = nom;
this.adresse = adresse;
}
public String toString(){
return nom + " - " + adresse;
} }
Pour être utilisable dans un flux d’objets la classe doit
être Serializable
Optionnel : permet de vérifier que la classe n’a pas été modifiée entre la sauvegarde et
la restauration d’un objet Les attributs doivent
être Serializable
Exemple2 : flux d'objets
Sauvegarde des objets:
Personne joe = new Personne("Joe", "1 rue du temple" );
Personne anne = new Personne("Anne", "2 avenue des écoles" );
try ( ObjectOutputStream oos =
new ObjectOutputStream(new FileOutputStream("C:/temp/test.obj")) ){ oos.writeObject(joe);
oos.writeObject(anne);
} catch (IOException e) {
System.err.println("erreur sur le flux");
}
Récupération des objets :
Personne p1, p2;
try ( ObjectInputStream ois =
new ObjectInputStream(new FileInputStream("C:/temp/test.obj")) ){ p1 = (Personne)ois.readObject();
p2 = (Personne)ois.readObject();
} catch (IOException e) {
System.err.println("erreur sur le flux");
} catch (ClassNotFoundException e) {
System.err.println("Type d'objet inconnu");
}
Système de fichiers : java.io.File
Quelques constructeurs
– File(String pathname)
– File(File parent, String child) – File(URI uri)
Quelques méthodes
– boolean exists( ) – boolean canRead( ) – boolean canWrite( ) – boolean isDirectory( ) – boolean isFile( )
– boolean createNewFile( ) – boolean delete( )
– boolean mkdir( )
– boolean renameTo(File dest) – String getAbsolutePath( ) – URI toURI( )
– String getName( ) – String getParent( ) – String[ ] list( )
– File[ ] listFiles( )
Choix d'un fichier : IHM
Avec l'AWT : java.awt.FileDialog
FileDialog chooser = new FileDialog(myFrame);
chooser.setMode(FileDialog.LOAD);
chooser.show();
System.out.println("You chose to open this file: " + chooser.getDirectory()+chooser.getFile());
Avec SWING : javax.swing.JFileChooser
JFileChooser chooser = new JFileChooser();
int returnVal = chooser.showOpenDialog(myFrame);
if(returnVal == JFileChooser.APPROVE_OPTION) {
System.out.println("You chose to open this file: " + chooser.getSelectedFile().getAbsolutePath());
}
Les fichiers à accès direct
Il existe aussi des fichiers à accès direct : java.io.RandomAccessFile
– RandomAccessFile(File file, String mode)
– RandomAccessFile(String name, String mode)
Lecture :
– int read( ) / int read(byte[ ] b) lecture d'un ou plusieurs octets
– boolean readBoolean( ) lecture d'un booléen
– int readInt( ) lecture d'un entier
– …
Écriture
– void write(byte b) / void write((byte[ ] b)
– void writeBoolean(boolean b) écriture d'un booléen
– void writeDouble(double v) lecture d'un double
– …
Déplacement
– long getFilePointer( ) position actuelle dans le fichier – void seek(long pos) déplacement par rapport au début du fichier – void skipBytes(int n) déplacement par rapport à la position actuelle – long length( ) / void setlength(long newLength) gestion de la taille du fichier – void close( )
Exemple : fichiers à accès direct
Sauvegarde :
RandomAccessFile f = new RandomAccessFile("c:/temp/test.dat", "rw");
for (int i = 0; i < 10; i++) { f.writeInt(i * 100);
}
f.close();
Récupération (on lit un entier sur 2 en commençant par la fin) :
RandomAccessFile f = new RandomAccessFile("c:/temp/test.dat", "r");
long i = f.length();
while (i >= 4) { f.seek(i-4);
System.out.println(f.readInt());
i = i – (2*4); //un entier fait 4 octets }
f.close();