Vous êtes sur la page 1sur 5

Grandes lignes du cours

Cours JAVA :
Les Entrées/Sorties en Java.
Version 0.02

L’abstraction Les sources/destinations


Julien Sopena1 Les types de flux Les filtres
Les filtres personnalisés
1 julien.sopena@lip6.fr

Équipe REGAL - INRIA Rocquencourt


LIP6 - Université Pierre et Marie Curie

Licence professionnelle DANT - 2015/2016

J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 1 / 39 J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 2 / 39

Outline Les Entrées/Sorties

Tous les programmes reposent sur des interactions avec le monde extérieur :
L’abstraction
I leurs actions dépendent d’ordres, de données et de paramètres reçus
Les types de flux
I leurs calculs produisent un ensemble de données et d’évènements
Les sources/destinations transmis à l’utilisateur ou à d’autres programmes.
Les filtres
Les filtres personnalisés Définition
On appelle Entrées/Sorties (E/S) l’ensemble des actions qui
servent respectivement à recevoir et produire des données quel que
soit le type d’interaction utilisée.

J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 3 / 39 J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 4 / 39

De multiples types d’interaction Les flux : abstractions d’interactions

Les Entrées/Sorties utilisent de nombreux supports (fichiers, Définition


réseaux, mémoire, ...) et leurs actions peuvent sembler assez Les flux (streams en anglais) permettent d’encapsuler les envois
éloignées. et les réceptions de données de façon à cacher le support utilisé.
Ainsi un même code utilisera indifféremment : un fichier, le réseau
ou la mémoire.
Éditer un fichier Lire un fichier
FluxSortie

Envoyer un message Recevoir un message


Écrire ? Lire
FluxEntrée

Char[]

Entrer une valeur Consulter une valeur


Attention
Modifier une chaîne "Chaîne" Récupérer une chaîne Les flux traitent toujours les données de façon séquentielle.

J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 5 / 39 J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 6 / 39

Encapsulation des entrées/sorties Encapsulation des entrées/sorties

Grâce à l’utilisation des flux on peut masquer l’hétérogénéité des Grâce à l’utilisation des flux on peut masquer l’hétérogénéité des
sources et des destinations. sources et des destinations.

Éditer un fichier Lire un fichier Écrire Lire

Envoyer un message Recevoir un message Écrire Lire

Char[] Char[]

Entrer une valeur Consulter une valeur Écrire Lire

Modifier une chaîne "Chaîne" Récupérer une chaîne Écrire "Chaîne" Lire

J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 7 / 39 J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 7 / 39
Les classes d’Entrée/Sortie de Java Outline

Java encapsule les entrées/sorties dans trois types de classes :


Les flux de base dont les types de la classe indiquent :
L’abstraction
I le sens du flux (Entrée ou Sortie)
I le type des données (Octet ou Caractère)
Les types de flux
Les sources/destinations
Les constructeurs dont les noms <Support><TypeFlux>
indiquent : Les filtres
I le support (ficher, tableau, chaîne, tube, ...) Les filtres personnalisés
I le flux de base utilisé

Les filtres dont les noms <Fonctionnalité><TypeFlux> indiquent :


I la fonctionnalité (buffer, serialisation, compression, ...)
I le flux de base utilisé

La suite du cours présente ces trois familles de Classe.

J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 8 / 39 J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 9 / 39

Les deux familles de flux : Octets / Caractères API des flux d’entrée en octets : InputStream

Définition int read() : lecture d’un octet


I bloquant tant qu’il n’y a rien à lire et que le flux reste ouvert.
Java distingue deux sortes de flux suivant le type de données manipulées : I l’octet lu est retourné sous forme d’un int
Flux d’octets : InputStream en entrée et OutputStream en sortie ; I retourne -1 si le flux est fermé

Flux de caractères : Reader en entrée et Writer en sortie ; int read( byte[] tab ) : lecture d’un tableau d’octet
I bloquant tant qu’il n’y a rien à lire et que le flux reste ouvert.
Pour éditer un fichier on peut, suivant ce que l’on veut stocker, utiliser : I retourne le nombre d’octet lu ou -1 si le flux est fermé
I Attention : le tableau doit être alloué avant l’appel à read
OutputStream
int read( byte[] tab, int offset, int length) :
Écrire des octets ? Lire des octets
I idem avec au plus length octets enregistrés à partir de la case offset
InputStream
long skip( long n ) : "saute" n octets (sans les retourner)
Writer
int available() : retourne le nombre d’octets disponible
Écrire des caractères Lire des caractères
Lorem ipsum
dolor sit a
met, consec
tetur adipi
scing elit.
I l’appel est non bloquant.
Reader void close() : fermeture du flux

J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 10 / 39 J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 11 / 39

API des flux de sortie en octets : OutputStream Exemple d’utilisation des flux d’octets
OutputStream

Écrire des octets ? Lire des octets


void write(byte b) : écriture d’un octet dans le flux InputStream

I Lève une exception en cas d’erreur.


void write( byte[] tab ) : écriture d’un tableau d’octet // Récupération du flux
// Récupération du flux
InputStream is = ?????? ;
OutputStream os = ?????? ;
void write( byte[] tab, int offset, int length) : écriture de length
octets à partir de la case offset // Utilisation du flux
// Utilisation du flux
int x,y ;
void flush() : vide les buffers en forçant l’écriture for (byte b=0; b<5 ;b++) {
while ((x=is.read())!=-1) {
os.write(b);
void close() : fermeture du flux y = is.read();
os.write(2*b+1);
dessin.trace(x,y);
}
}
// Fermeture du flux
// Fermeture du flux
os.close();
is.close();

J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 12 / 39 J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 13 / 39

Exemple d’utilisation des flux de caractères Outline


Writer

Écrire des caractères ? Lire des caractères


Reader L’abstraction
Les types de flux
// Récupération d’un flux Les sources/destinations
// Récupération d’un flux Reader r = ?????? ; Les filtres
Writer w = ?????? ;
// Utilisation du flux Les filtres personnalisés
// Utilisation du flux StringBuffer buff = ...
w.write(’a’); int i;
w.write(’b’); while ((i=r.read())!=-1) {
w.write("cdef"); buff.append((char)i);
}
// Fermeture du flux
w.close(); // Fermeture du flux
r.close();

J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 14 / 39 J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 15 / 39
Où trouve t-on les flux ? Les flux standard : la console et le clavier
La classe System est pourvue de trois attributs de classe :
On distingue deux méthodes pour obtenir la référence d’un flux : in : un flux qui correspond à l’entrée standard (par défaut le clavier)
1. Par accesseur : certaines classes de Java possèdent des flux out : un flux qui correspond à la sortie standard (par défaut la console)
pour produire ou recevoir des données. Ceux-ci sont err : un flux qui correspond à la sortie d’erreur (par défaut la console)
accessibles directement (System.in et System.out) ou au
travers d’accesseurs (getInputStream() et // Lecture sur le clavier
int x = System.in.read() ;
getOutputStream()).
2. Par constructeur : pour les objets qui ne possèdent pas // Écriture sur la console
System.out.write(x);
directement de flux, Java offre pour les construire des classes
spécifiques à chaque support. Toutes ces classes héritent d’un
des 4 flux de base : InputStream, OutputStream, Reader ou
Attention
Writer.
En réalité les sorties out et err utilisent un filtre PrintStream (voir
Dans tous les cas, une fois obtenu la référence : plus loin) qui permet l’utilisation des fonctions print et println.
on utilise le flux indifféremment du type de sources/destinations.

J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 16 / 39 J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 17 / 39

Exemple de classe munie d’un flux : Process Classes permettant de construire des flux
OutputStream
Dans le cas de la classe Process les flux permettent d’écrire (resp.
de lire) sur l’entrée standard (resp. la sortie standard) du processus.
Écrire des octets ? Lire des octets
InputStream

// Lancement du programme beep Source / Destination Entrée en Octets Sortie en Octets


Process p = (Défini avec un préfixe) (Hérite de InputStream) (Hérite de OutputStream)
Runtime.getRuntime().exec("beep -c -f 400 -D 50 -l 10"); Tableau d’octets en mémoire : ByteArrayInputStream ByteArrayOutputStream
Fichier : FileInputStream FileOutputStream
// Récupération du flux d’entrée standard du programme Pipeline entre deux threads : PipedInputStream PipedOutputStream
// ATTENTION : Pour nous c’est un flux de sortie (out) Chaîne de caractères : StringBufferInputStream StringBufferOutputStream
OutputStream os = p.getOutputStream();
Writer

// Utilisation du flux : comme avec tout OutputStream Écrire des caractères ? Lire des caractères
int x; Reader
while ( (x = System.in.read()) != -1 ) {
Source / Destination Entrée en Caractères Sortie en Caractères
os.write(x);
(Défini avec un préfixe) (Hérite de Reader) (Hérite de Writer)
}
Tableau de caractères en mémoire : CharArrayReader CharArrayWriter
Fichier : FileReader FileWriter
// Fermeture du flux (=> arrêt du programme beep)
os.close(); Pipeline entre deux threads : PipedReader PipedWriter
Chaîne de caractères : StringReader StringWriter

J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 18 / 39 J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 19 / 39

Exemple d’utilisation d’un fichier d’octets Exemple d’utilisation d’un fichier d’octets
OutputStream OutputStream

Écrire des octets ? Lire des octets Écrire des octets ? Lire des octets
InputStream InputStream

// Récupération du flux // Récupération du flux


// Récupération du flux // Récupération du flux
InputStream is = InputStream is =
OutputStream os = OutputStream os =
?????????????????? ; new FileInputStream("foo");
?????????????????? ; new FileOutputStream("foo");
// Utilisation du flux // Utilisation du flux
// Utilisation du flux // Utilisation du flux
int x,y ; int x,y ;
for (byte b=0; b<5 ;b++) { for (byte b=0; b<5 ;b++) {
while ((x=is.read())!=-1) { while ((x=is.read())!=-1) {
os.write(b); os.write(b);
y = is.read(); y = is.read();
os.write(2*b+1); os.write(2*b+1);
dessin.trace(x,y); dessin.trace(x,y);
} }
} }
// Fermeture du flux // Fermeture du flux
// Fermeture du flux // Fermeture du flux
os.close(); os.close();
is.close(); is.close();

J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 20 / 39 J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 21 / 39

Exemple d’utilisation d’un tableau d’octets Exemple d’utilisation d’un fichier de caractères
OutputStream Writer

?
byte[]

Écrire des octets Lire des octets Écrire des caractères Lire des caractères
InputStream Reader

// Récupération du flux // Récupération d’un flux


// Récupération du flux
InputStream is = // Recupération d’un flux Reader r =
OutputStream os =
new ByteArrayInputStream(t); Writer w = ?????????????????? ;
new ByteArrayOutputStream(t);
?????????????????? ;
// Utilisation du flux // Utilisation du flux
// Utilisation du flux
int x,y ; // Utilisation du flux StringBuffer buff = ...
for (byte b=0; b<5 ;b++) {
while ((x=is.read())!=-1) { w.write(’a’); int i;
os.write(b);
y = is.read(); w.write(’b’); while ((i=r.read())!=-1) {
os.write(2*b+1);
dessin.trace(x,y); w.write("cdef"); buff.append((char)i);
}
} }
// Fermeture du flux
// Fermeture du flux
// Fermeture du flux w.close(); // Fermeture du flux
os.close();
is.close(); r.close();

J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 22 / 39 J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 23 / 39
Exemple d’utilisation d’un fichier de caractères Exemple d’utilisation d’un tableau de caractères
Writer Writer
char[]

Écrire des caractères Lire des caractères Écrire des caractères Lire des caractères
Lorem ipsum
dolor sit a
met, consec
tetur adipi
scing elit.

Reader Reader

// Récupération d’un flux // Récupération d’un flux


// Récupération d’un flux Reader r = // Récupération d’un flux Reader r =
Writer w = new FileReader("foo.txt"); Writer w = new CharArrayReader(t);
new FileWriter("foo.txt"); new CharArrayWriter(t);
// Utilisation du flux // Utilisation du flux
// Utilisation du flux StringBuffer buff = ... // Utilisation du flux StringBuffer buff = ...
w.write(’a’); int i; w.write(’a’); int i;
w.write(’b’); while ((i=r.read())!=-1) { w.write(’b’); while ((i=r.read())!=-1) {
w.write("cdef"); buff.append((char)i); w.write("cdef"); buff.append((char)i);
} }
// Fermeture du flux // Fermeture du flux
w.close(); // Fermeture du flux w.close(); // Fermeture du flux
r.close(); r.close();

J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 24 / 39 J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 25 / 39

Outline Les filtres de base en Java

Définition
Pour ajouter des fonctionnalités aux flux, Java utilise des classes appelées
L’abstraction filtre suivant le patron de conception (design-pattern) du décorateur.
Les types de flux
Les sources/destinations Le nom des filtres Java est suffixé par l’un des quatre flux de base :
Les filtres I ils héritent de Filter<FluxBase> qui hérite de <FluxBase> ;
Les filtres personnalisés I ils prennent ce flux comme paramètre de leur constructeur.

Pour ajouter des fonctionnalités ils peuvent :


I redéfinir le fonctionnement des méthodes de base (read, write, ...)
=⇒ par polymorphisme l’utilisation est transparente et interchangeable
I ajouter de nouvelles méthodes (print, writeBoolean, readLine, ...)

J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 26 / 39 J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 27 / 39

Les filtres de base en Java InputStreamReader et OutputStreamWriter


am

Les Filtres par flux


m

Attention
tp rea

ad tre
t

S
tS

ut

Wr r
er
e

Il ne faut pas confondre les utilisations des termes InputStream et


pu

it
In

Ou

Re

Préfixe Fonctionnalité OutputStream pour désigner des flux, avec leurs utilisations comme
Buffered : Mise en tampon nom des constructeurs permettant de construire des flux de carac-
tères à partir de flux en caractères.
Data : Conversion des types primitifs
Object : Sérialisation d’objet
En tant que flux, il sont des suffixes comme dans :
Sequence : Concaténation de flux
I BufferedInputStream, ObjectInputStream, DataInputStream
Print : Fonctions de formatage print I BufferedOutputStream, ObjectOutputStream, DataOutputStream
PushBack : Lecture avec remise dans le flux
En tant que constructeurs, il sont des préfixes comme dans :
LineNumber : Numérotation des lignes I InputStreamReader
Digest : Vérification par somme de contrôle I OutputStreamWriter
Cipher : Chiffrage du flux
J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 28 / 39 J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 29 / 39

Composition de filtres Composition de filtres


CypherOutputStream
OutputStream OutputStream

? ?
InputStream InputStream
CypherInputStream

OutputStream os = ?????? ; OutputStream os = ?????? ;


CipherOutputStream cos = new CipherOutputStream(os, cipher);

for (byte b=0 ; b<3 ; b++) { for (byte b=0 ; b<3 ; b++) {
os.write(b); cos.write(b);
} }
os.close(); cos.close();

InputStream is = ?????? ; InputStream is = ?????? ;


CipherInputStream cis = new CipherInputStream(is, cipher);

while ( (x = is.read()) != -1 ) { while ( (x = cis.read()) != -1 ) {


System.out.println(x); System.out.println(x);
} }
is.close(); cis.close();

J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 30 / 39 J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 31 / 39
Composition de filtres Composition de filtres
BufferedOutputStream
GZIPOutputStream GZIPOutputStream
CypherOutputStream CypherOutputStream
OutputStream OutputStream

? ?
InputStream InputStream
CypherInputStream CypherInputStream
GZIPInputStream GZIPInputStream
BufferedInputStream

OutputStream os = ?????? ; OutputStream os = ?????? ;


CipherOutputStream cos = new CipherOutputStream(os, cipher); CipherOutputStream cos = new CipherOutputStream(os, cipher);
GZIPOutputStream zcos = new GZIPOutputStream(cos); GZIPOutputStream zcos = new GZIPOutputStream(cos);
BufferedOutputStream bzcos = new BufferedOutputStream(zcos);
for (byte b=0 ; b<3 ; b++) { for (byte b=0 ; b<3 ; b++) {
zcos.write(b); bzcos.write(b);
} }
zcos.close(); bzcos.close();

InputStream is = ?????? ; InputStream is = ?????? ;


CipherInputStream cis = new CipherInputStream(is, cipher); CipherInputStream cis = new CipherInputStream(is, cipher);
GZIPInputStream zcis = new GZIPInputStream(cis); GZIPInputStream zcis = new GZIPInputStream(cis);
BufferedInputStream bzcis = new BufferedInputStream(zcis);
while ( (x = zcis.read()) != -1 ) { while ( (x = bzcis.read()) != -1 ) {
System.out.println(x); System.out.println(x);
} }
zcis.close(); bzcis.close();

J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 32 / 39 J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 33 / 39

Composition de filtres Attention à l’ordre des filtres : efficacité


BufferedOutputStream
GZIPOutputStream
CypherOutputStream
OutputStream L’ordre de mise en œuvre des filtres peut avoir une grande
? incidence sur les performances du programme.
InputStream
CypherInputStream
GZIPInputStream
BufferedInputStream
Comparons par exemple les séquences suivantes :
OutputStream os = new BufferedOutputStream(
BufferedOutputStream
new GZIPOutputStream( GZIPOutputStream
CypherOutputStream
new CipherOutputStream(??????, cipher) OutputStream

));
for (byte b=0 ; b<3 ; b++) { ?
InputStream
os.write(b); CypherInputStream
GZIPInputStream
} BufferedInputStream
BufferedOutputStream
os.close(); CypherOutputStream
GZIPOutputStream
OutputStream

?
InputStream is = new BufferedInputStream(
new GZIPInputStream(
InputStream
new CipherInputStream(??????, cipher) GZIPInputStream
CypherInputStream
)); BufferedInputStream

while ( (x = is.read()) != -1 ) {
System.out.println(x); Les opérations cryptographiques sont très coûteuses en calculs :
}
is.close(); il est donc préférable de compresser le flux avant de le crypter.

J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 34 / 39 J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 35 / 39

Attention à l’ordre des filtres : cohérence Outline

Attention
Attention l’ordre des filtres utilisés lors de la lecture du flux d’en- L’abstraction
trée doit être compatible avec celui utilisé pour produire les don- Les types de flux
nées dans le flux de sortie
Les sources/destinations
BufferedOutputStream
GZIPOutputStream
Les filtres
CypherOutputStream
OutputStream Les filtres personnalisés
?
InputStream
GZIPInputStream
CypherInputStream
BufferedInputStream

java Reception
Exception in thread "main" java.util.zip.ZipException: Not in GZIP format
at java.util.zip.GZIPInputStream.readHeader(GZIPInputStream.java:164)
at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:78)
at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:90)
at flux.FluxBZC.main(Reception.java:10)

J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 36 / 39 J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 37 / 39

Implémenter ses propres filtres Exemple de filtre personnalisé : fonction linéaire


Les fonctionnalités offertes par Java sont insuffisantes : public class LinearInputStream extends FilterInputStream {
int a,b;
=⇒ implémentez un filtre en suivant le design-pattern du décorateur. protected LinearInputStream(InputStream is,int a, int b) {
super(is);
this.a=a;
Pour un filtre personnalisé destiné à la lecture d’octets : this.b=b;
I définir une classe qui hérite de FilterInputStream ; }
@Override
I implémenter un constructeur à un paramètre InputStream is : public int read() throws IOException {
1. appeler à la première ligne du constructeur super(is) int x = super.read() ;
return a*x+b ;
2. si besoin enregistrer les autres paramètres dans des attributs }
I redéfinir la méthode read() }
1. utiliser super.read() pour obtenir la valeur avant transformation
2. appliquer le filtre InputStream is =
3. retourner la valeur modifiée new FileInputStream("f1");
OutputStream os =
LinearInputStream lis =
new FileOutputStream("f1");
new LinearInputStream(is,2,3);
os.write(1);
Attention, une fois implémentés vos filtres personnalisés os.close();
int y = lis.read();
System.out.println("y="+y);
devront s’utiliser comme tous les autres filtres standards de Java. lis.close();

J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 38 / 39 J. Sopena (INRIA/UPMC) Les Entrées/Sorties en Java. 39 / 39