Chapitre VII : Les flux en Java
Interractions avec le syst` eme d’exploitation
D´epartement IEM
http://ufrsciencestech.u-bourgogne.fr http://ludique.u-bourgogne.fr/~leclercq
24 avril 2008
Plan
1 Le mod`ele de flux Organisation de l’API
Manipulation des flux binaires Entr´ees-sorties de type terminal Les tubes
2 Flux et fichiers
Exemple de flux connect´e `a un fichier
3 Persistance d’objet et s´erialisation Principes
Exemples
4 Connecter un flux `a une ressource Web
5 Java nio
Le mod`ele de canaux Canaux et fichiers Verrouillage
Principes et d´ efinitions
Les entr´ees / sorties sont organis´ees en Java autour du concept de flux ou flot (stream)
D´efinition :
Un flux est un canal de communication entre un lecteur et un r´edacteur.
Les flux sont classifi´es en :
flux d’entr´ee qui comportent des m´ethodes de lecture ; flux de sortie qui comportent des m´ethodes d’´ecriture.
Un flux d’entr´ee est connect´e `a une source, un flux de sortie `a une cible.
La source ou la cible d’un flux peuvent ˆetre un fichier, un tampon en m´emoire, une chaˆıne de caract`eres, une connexion r´eseau, un autre flux.
Organisation de l’API
L’API Java propose une infrastructure de flux bas´ee sur les packagesjava.io et java.nio.
Les flux sont des objets
Tous les flux sont des descendants des classes (abstraites) InputStream,OutputStream,ReaderetWriter.
Les flux ´el´ementaires sont des flux d’octets (flux binaires).
Les classes pour les flux non structur´es (s´equences d’octets) en ´ecriture, respectivement lecture, sont OutputStream respectivement InputStream (suffixes).
Les classes pour les flux de type s´equences de caract`eres Unicode, en ´ecriture, respectivement lecture, sontWriteret respectivement Reader(suffixes).
Les classes InputStreamReaderet OutputStreamWriter sont des ponts entre les flux structur´es et non structur´es.
Les classes construites ` a partir d’InputStream
ObjectInputStream FileInputStream ByteArrayInputStream FilterInputStream
PipedInputStream SequenceInputStream StringBufferInputStream
BufferedInputStream DataInputStream PushBackInputStream LineNumberInputStream Object
File InputStream
Les classes construites ` a partir d’OutputStream
ObjectInputStream FileInputStream ByteArrayInputStream FilterInputStream
PipedInputStream SequenceInputStream StringBufferInputStream
BufferedInputStream DataInputStream PushBackInputStream LineNumberInputStream Object
File InputStream
Lecture et ´ ecriture des flux binaires
InputStream et OutputStream sont les classes de base qui d´efinissent l’interface de plus bas niveau des flux d’octets.
Les m´ethodes g´en´erales de lecture sur un flux d’octets sont : int read() : lit l’octet suivant disponible sur le flux (se bloque en l’attendant) et retourne la valeur lue dans un int (valeur entre 0 et 255), retourne -1 si la fin du flux est atteinte ;
int read(byte b[])lit au plus b.lengthoctets depuis le flux, les placent dans le tableau b, et retourne le nombre d’octets lus ou bien -1 si la fin du flux est atteinte.
Les m´ethodes g´en´erales d’´ecriture sur un flux d’octets sont : void write(int c)´ecrit un octet, repr´esent´e par un int void write(byte[] b)´ecrit lesb.lengthoctets de b
Entr´ ees-sorties de type terminal
La classejava.lang.System d´efini les E/S standard : in,out, err.
Par comparasion avec C on peut ´etablir la correspondance :
1 I n p u t S t r e a m s t d i n = S y s t e m . in ; 2 O u t p u t S t r e a m s t d o u t = S y s t e m . out ; 3 O u t p u t S t r e a m s t d e r r = S y s t e m . err ;
outet errne sont pas r´eellement des OutputStreammais des PrintStream sp´ecialis´es et tr`es utiles pour l’affichage.
Il est possible de lire un caract`ere sur l’entr´ee standard avec la m´ethode read()et de tester la fin du flux (valeur retourn´ee -1) :
1 try{ int val = S y s t e m . in . r e a d () ; } 2 c a t c h ( I O E x c e p t i o n e ) {}
3 ...
4 b y t e b =(b y t e) val ;
Entr´ ees-sorties de type terminal
Toutes les op´eration de lecture et d’´ecriture sur les flux peuvent d´eclencher une exception IOException.
la m´ehtode available() permet de v´erifier le nombre d’octets disponibles lors de la lecture pour cr´eer ensuite la structure avec la taille adapt´ee.
1 int a t t e n t e = S y s t e m . in . a v a i l a b l e () ; 2 b y t e d a t a []=new b y t e[ a t t e n t e ];
3 S y s t e m . in . r e a d ( d a t a ) ;
la m´ethode close() lib`ere les ressources syst`eme allou´ees.
InputStream propose la m´ethode skip()pour sauter un certain nombre de d’octets.
Les enveloppes de flux
Ce principe consiste `a ajouter des fonctionnalit´es au flux.
Le plus souvent il s’agit de transformations ou de filtrage.
Un flux filtre prendre le flux cible comme argument de son constructeur et lui d´el`egue les appels avec avoir effectu´e ses op´eration de filtrage
f2.écrire()
f1.écrire() Flux f1
Flux f2
Pont entre les flux de caract` eres et d’octets
InputStreamReader etOutputStreamWritersont des flux de caract`eres enveloppant un flux d’octets.
Un sch´ema d’encodage permet une conversion dans les deux sens.
Le mod`ele de d’encodage peut ˆetre donn´e en param`etre au constructeur.
1 try{
2 I n p u t S t r e a m R e a d e r c o n v e r t = new I n p u t S t r e a m R e a d e r ( S y s t e m . in ) ; 3 // on e n v e l o p p e d a n s B u f f e r e d R e a d e r p o u r b ´e n ´e f i c i e r de r e a d L i n e () 4 B u f f e r e d R e d e r in = new B u f f e r e d R e a d e r ( c o n v e r t ) ;
5 S t r i n g t e s t e = in . r e a d L i n e () ;
6 int i = N u m b e r F o r m a t . g e t I n s t a n c e () . p a r s e ( t e x t e ) . i n t V a l u e () ;
7 }
8 c a t c h( I O E x c e p t i o n e ) { . . . } 9 c a t c h( P a r s e E x c e p t i o n pe ) { . . . }
Pont entre les flux de caract` eres et d’octets
InputStream DataInputStream
read() readFloat() readInt() readLong() ...
...
write() writeFloat() writeInt()
writeLong() DataOutputStream
OutputStream
Les tubes (pipes)
D´efinition :
PipedOutputStreamet PipedInputStream permettent de connecter les ext´emit´es des flux
Les pipes permettent de faire communiquer les thread sans passer par des structures globales (static)
PipedOutputStream
PipedInputStream Thread A
Thread B write()
read()
le tube
Les tubes (pipes)
Exemple de cr´eation et connexion de tubes :
1 P i p e d I n p u t S t r e a m t u b e E n t r e e = new P i p e d I n p u t S t r e a m () ;
2 P i p e d O u t p u t S t r e a m t u b e S o r t i e = new P i p e d O u t p u t S t r e a m ( t u b e E n t r e e ) ;
L’ordre inverse de cr´eation est aussi possible ;
Il est possible de cr´eer les tubes s´epar´ement et de les connecter ensuite dynamiquement au moyen de la m´ethodeconnect(); Les fluxPipedReader et PipedWriter sont r´eserv´es aux flux de caract`eres ;
Si lebuffer interne du tube est plein le processus qui ´ecrit est bloqu´e et mis en attente jusqu’a ce que le processus qui lit est fait de la place ;
De fa¸con sym´etrique, le processus lecteur est bloqu´e si le buffer est vide.
Les tubes (pipes) : un exemple
Processus de lecture d’un flux (fichier) :
1 i m p o r t j a v a . io . B u f f e r e d R e a d e r ; 2 i m p o r t j a v a . io . I O E x c e p t i o n ; 3 i m p o r t j a v a . io . P r i n t W r i t e r ;
4 p u b l i c c l a s s L e c t e u r e x t e n d s T h r e a d { 5 p r i v a t e P r i n t W r i t e r out = n u l l; 6 p r i v a t e B u f f e r e d R e a d e r in = n u l l;
7 p u b l i c L e c t e u r ( P r i n t W r i t e r out , B u f f e r e d R e a d e r in ) { 8 t h i s. out = out ;
9 t h i s. in = in ;
10 }
11 p u b l i c v o i d run () {
12 if ( out != n u l l && in != n u l l) {
13 try {
14 S t r i n g i n p u t ;
15 w h i l e (( i n p u t = in . r e a d L i n e () ) != n u l l) { 16 out . p r i n t l n ( i n p u t . t o U p p e r C a s e () ) ;
17 out . f l u s h () ;
18 }
19 out . c l o s e () ;
20 } c a t c h ( I O E x c e p t i o n e ) { e . p r i n t S t a c k T r a c e () ; }
21 }
22 }
23 }
Les tubes (pipes) : un exemple
Processus connect´e au tube :
1 i m p o r t j a v a . io . B u f f e r e d R e a d e r ; 2 i m p o r t j a v a . io . F i l e R e a d e r ; 3 i m p o r t j a v a . io . P i p e d R e a d e r ; 4 i m p o r t j a v a . io . P i p e d W r i t e r ; 5 i m p o r t j a v a . io . P r i n t W r i t e r ; 6 p u b l i c c l a s s E x e m p l e T u b e {
7 p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) t h r o w s E x c e p t i o n { 8 F i l e R e a d e r f =new F i l e R e a d e r ( " t o t o . txt " ) ;
9 B u f f e r e d R e a d e r in =new B u f f e r e d R e a d e r ( f ) ; 10
11 P i p e d W r i t e r p i p e O u t = new P i p e d W r i t e r () ; 12 P i p e d R e a d e r p i p e I n = new P i p e d R e a d e r ( p i p e O u t ) ; 13
14 P r i n t W r i t e r out = new P r i n t W r i t e r ( p i p e O u t ) ; 15 new L e c t e u r ( out , in ) . s t a r t () ;
16
17 B u f f e r e d R e a d e r bin = new B u f f e r e d R e a d e r ( p i p e I n ) ; 18 S t r i n g i n p u t ;
19
20 w h i l e (( i n p u t = bin . r e a d L i n e () ) != n u l l) { 21 S y s t e m . out . p r i n t l n ( i n p u t ) ;}
22 in . c l o s e () ;
23 }
24 }
Connecter un flux ` a un fichier (exemple)
La lecture et l’´ecriture d’octets dans un fichier se fait `a l’aide des classesFileInputStream etFileOutputStream
1 i m p o r t j a v a . io .*;
2 c l a s s C o p i e B i n a i r e F i c h i e r {
3 p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) 4 t h r o w s I O E x c e p t i o n {
5 ...
6 int c ;
7 ...
8 if ( a r g s . l e n g t h > 0) in = new F i l e I n p u t S t r e a m ( a r g s [ 0 ] ) ; 9 if ( a r g s . l e n g t h > 1) out = new F i l e O u t p u t S t r e a m ( a r g s [ 1 ] ) ; 10 w h i l e (( c = in . r e a d () ) != -1) out . w r i t e ( c ) ;
11 in . c l o s e () ;
12 out . c l o s e () ;
13 }
Association de flux pour la gestion des fichiers
D´efinition :
DataInputStreametDataOutputStream sont des flux filtrants qui permettent de lire ou d’´ecrire des chaˆınes de catact`eres et des types de base cod´es sur plusieurs octets.
DataInputStream etDataOutputStream impl´ementent les interfaces DataInputet DataOutput.
Elles offrent des m´ethodes plus ´evolu´ees que FileOutputStream et FileInputStream
Elles proposent des m´ethodes pour envoyer des types primitifs dans le flux : writeIntetc.
L’exemple suivant montre l’enrichissement, l’association et la connexion de flux.
Un objet de type file peut ˆetre utilis´e dans les constructeurs de flux.
Association de flux pour la gestion des fichiers
Exemple d’association avec le flux d’entr´ee standard
1 D a t a I n p u t S t r e a m dis = new D a t a I n p u t S t r e a m ( S y s t e m . in ) ; 2 d o u b l e d = dis . r e a d D o u b l e () ;
Exemple d’association avec un fichier
1 ...
2 F i l e O u t p u t S t r e a m f = new F i l e O u t p u t S t r e a m ( " fic . dat " ) ; 3 D a t a O u t p u t S t r e a m s o r t i e = new D a t a O u t p u t S t r e a m ( f ) ;
4 ...
5 D a t a O u t p u t S t r e a m s o r t i e = new D a t a O u t p u t S t r e a m ( 6 new F i l e O u t p u t S t r e a m ( " fic . dat " ) ;
7 ...
Obtenir les propri´ et´ es d’un fichier
java.io.File est utile pour obtenir diverses propri´et´es de fichiers :
savoir si un chemin d´esigne un fichier ordinaire ou un r´epertoire savoir si l’objet est accessible en lecture ou en ´ecriture, etc.
1 F i l e c h e m i n R e p e r t o i r e =
2 new F i l e ( " / usr / l o c a l / j a v a / d o c s " ) ; 3 F i l e c h e m i n F i c h i e r =
4 new F i l e ( c h e m i n R e p e r t o i r e , " i n d e x . h t m l " ) ;
5 ...
6 if ( c h e m i n R e p e r t o i r e . i s D i r e c t o r y () &&
7 c h e m i n F i c h i e r . c a n R e a d () ) {
8 ...
9 }
Les constructeurs de fichier ne l`event pas d’exception.
Obtenir les propri´ et´ es syst` eme
Il est possible de consulter les propri´et´es syst`eme (System Properties) : System.getProperty("cl´e") ;. La cl´e peut prendre les valeurs suivantes :
file.separator line.separator user.dir
java.version java.home
java.class.path etc.
Op´ erations principales sur les fichiers
M´ethode Type retour Description
canRead() Boolean le fichier ou le r´epertoire est-il accessible en lecture ?
canWrite() Boolean le fichier ou le r´epertoire est-il accessible en ´ecriture ?
createNewFile() Boolean Cr´ee un nouveau fichier
delete() Boolean d´etruit le fichier ou le r´epertoire
exists() Boolean est-ce que le fichier ou le r´epertoire existe ?
getAbsolutePath() String renvoie le chemin absolu du fichier ou du r´epertoire
getName() String renvoie le nom du fichie ou du r´epertoire
getParent() String renvoie le nom du r´epertoire parent du fichier ou du r´epertoire
getPath() String renvoie le chemin du fichier ou du r´epertoire
isAbsolute() Boolean le chemin du fichier ou du r´epertoire est-il absolu
isDirectory() Boolean s’agit-il d’un r´epertoire ?
isFile() Boolean s’agit-il d’un fichier ?
lastModified() long renvoie la date de la derni`ere modification du fichier ou du r´epertoire
length() long renvoie la taille du fichier
list() String [] renvoie la liste des fichiers du r´epertoire
listfiles() File [] renvoie la liste des fichiers du r´epertoire sous la forme d’un tableau d’objet de typeFile
mkdir() Boolean cr´ee un r´epertoire
mkdirs() Boolean cr´ee tous les r´epertoires du chemin
renameTo(File dest) Boolean renome le fichier ou le r´epertoire
setLastModified() Boolean d´efinit l’heure de la derni`ere modification du fichier ou du r´epertoire
setReadOnly() Boolean d´efinit le fichier en lecture seule
toURL() java.net.URL g´en`ere un objet URL pour ce fichier ou r´epoertoire
Fichiers ` a acc` es direct
La classe RandomAccessFile peut ˆetre utilis´ee si un acc`es direct `a une position quelconque du fichier est n´ecessaire Fonctionne `a la fois en ´ecriture et en lecture
Un cuseur permet de se d´eplacer dans le fichier Il faut lui adjoindre un index pour trouver les ´el´ements Il faut ˆetre capable de d´eterminer (calculer) la position d’un
´
el´ements en fonction de sa taille
Le constructeur RandomAccessFile(String name, String mode) s’emploie avec une chaˆıne de caract`eres contenant le nom de fichier suivi du mode d’acc`esrpour lecture ou rw pour lecture et ´ecriture.
Le constructeur RandomAccessFile(File file, String mode) fait de mˆeme `a partir d’un objet File
Fichiers ` a acc` es direct
Pour naviguer dans le fichier :
utiliser un pointeur qui indique la position dans le fichier ou les op´erations de lecture ou de mise `a jour doivent ˆetre effectu´ees ; la m´ethodegetFilePointer()permet de connaˆıtre la position du pointeur
la m´ethodeseek()permet de d´eplacer le pointeur : en param`etre un entier long qui r´epr´esentent la position, dans le fichier, pr´ecis´ee en octets (la premi`ere position commence `a z´ero).
1 i m p o r t j a v a . io . R a n d o m A c c e s s F i l e ; 2 p u b l i c c l a s s T e s t R a n d o m A c c e s F i l e { 3 p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) {
4 try {
5 R a n d o m A c c e s s F i l e m o n F i c h i e r = new R a n d o m A c c e s s F i l e ( " m o n f i c h i e r . dat " , " rw " )
;
6 m o n F i c h i e r . s e e k ( 5 * 4 ) ; // x * s i z e o f int 7 S y s t e m . out . p r i n t l n ( m o n F i c h i e r . r e a d I n t () ) ; 8 m o n F i c h i e r . c l o s e () ;
9 } c a t c h ( E x c e p t i o n e ) { 10 e . p r i n t S t a c k T r a c e () ;
11 }
12 }
13 }
Lire et ´ ecrire sur un flux de caract` eres
Les flux de caract`eres sont des objets de classeReaderou Writer
Les m´ethodes read etwrite de ces classes sont analogues `a celles op´erant sur des flux d’octets, `a la diff´erence que c’est un caract`ere 16 bits qui est lu ou ´ecrit, et non un octet La conversion entre un flux d’octets et un flux de caract`eres se fait au moyen des classes OutputStreamWriteret InputStreamReader
Le principe est l’association de flux : connecter un flux d’octets `a un flux de caract`eres
InputStreamReader isr = new InputStreamReader(System.in) ;
Pour connecter un flux de caract`eres `a un fichier, si la conversion n’est pas n´ecessaire, il est plus simple de recourir aux classe FileWriteret FileReader
Connecter un flux ` a un tampon
Les op´erations individuelles de lecture ou d’´ecriture peut ˆetre tr`es coˆuteuses
C’est le cas des acc`es `a un fichier, ou des acc`es au r´eseau Pour ´eviter des op´erations individuelles sur un octet ou sur un caract`ere `a la fois, on utilise un tampon (buffer)
Pour ´ecrire sur un fichier on ´ecrira dans un flux bufferis´e Les classes qui mettent en oeuvre les buffers sont :
BufferedInputStreametBufferedOutputStreampour les flux binaires
BufferedReaderetBufferedWriterpour les flux de caract`eres
Connecter un flux ` a un tampon
Un flux de caract`eres de la classe BufferedReaderpropose des op´erations suppl´ementaires (par exemple, lecture d’une ligne de texte).
BufferedReader in =
new BufferedReader(new FileReader("toto"));
String s = in.readline();
De fa¸con similaire pour ´ecrire dans un fichier, il est pr´ef´erable de travailler avec un tampon :
PrintWriter out = new PrintWriter(
new BufferedWriter(
new FileWriter("toto")));
out.println("un long texte");
Lire et ´ ecrire des donn´ ees brutes sur un flux binaire
pour lire et ´ecrire, non pas des octets, mais des valeurs d’un type connu, il faut utiliser les classesDataInputStreamet
DataOutputStream
Ces classes disposent de m´ethodes sp´ecialis´ees pour les types primitifs :readInt(),readDouble(),readChar(),
readBoolean()(et les m´ethodes writeXYZ correspondantes) DataOutputStream dos = new DataOutputStream(
new FileOutputStream(’toto.dat’));
...
dos.writeBoolean(false);
dos.writeInt(400);
...
dos.close();
Mˆeme exemple pour lire un entier sur l’entr´ee standard : DataInputStream dis =
new DataInputStream(System.in);
int n = dis.readInt();
Lire et ´ ecrire des donn´ ees par blocs
Les flux peuvent ˆetre utilis´es afin de lire ou d’´ecrire des donn´ees par bloc (tableau d’octets)
Supposons que l’on dispose d’un tableau d’octets data re¸cu par exemple depuis une connexion r´eseau :
on sait que ce tableau contient un bool´een et un entier on utilise les flux des classesDataInputStreamet ByteArrayInputStream
byte[] data = ...;
DataInputStream dis = new DataInputStream(
new ByteArrayInputStream(data));
...
boolean b = dis.readBoolean();
int n = dis.readInt();
dis.close();
Lire et ´ ecrire des donn´ ees par blocs
Le tableau doit continir des donn´ees cod´ees de fa¸con compatible avec le d´ecodage r´ealis´e
Ce sera le cas si le tableau d’octets a ´et´e obtenu par les classes DataOutputStream etByteArrayOutputStream byte[] data;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeBoolean(true);
dos.writeInt(4);
data = baos.toByteArray();
dos.close();
Principes
Les classes ObjectOutputStreametObjectInputStream permettent de rendre persistants des objets de Java en les sauvegardant au travers d’un flux associ´e `a un fichier Si un objet comporte des membres qui sont des r´ef´erences `a d’autres objets ces objets persistent aussi.
Afin de pouvoir s´erialiser un objet d’une classe donn´ee, celle-ci doit impl´ementer l’interface Serializable ou h´eriter d’une classe elle-mˆeme s´erialisable.
L’interface Serializablene poss`ede aucun attribut et aucune m´ethode, elle sert uniquement `a identifier une classe s´erialisable.
Tous les attributs de l’objet sont s´erialis´es mais `a certaines conditions :
ˆ
etre lui-mˆeme s´erialisable ou ˆetre un type primitif ne pas ˆetre d´eclar´estatic
ne pas ˆetre d´eclar´e `a l’aide du mot cl´e transient
Exemple de cr´ eation
UnserialVersionUID est un num´ero de version, associ´e `a toute classe impl´ementant l’interface Serializable.
il permet de s’assurer que lors de la d´es´erialisation les versions des classes Java sont concordantes.
Si le test ´echoue, une InvalidClassException est lev´ee.
Une classe s´erialisable peut d´eclarer explicitement son serialVersionUID
Si une classe s´erialisable ne d´eclare pas explicitement un serialVersionUID, Java en calcule un par d´efaut.
Il est fortement recommand´e de d´eclarer explicitement le serialVersionUID.
private static final long serialVersionUID = 123L;
ObjectOutputStream s =
new ObjectOutputStream(new FileOutputStream("toto.dat"));
s.writeObject("Aujourd’hui");
s.writeObject(new Date());
Exemple de restitution
La lecture de ces objets se fait dans le mˆeme ordre que leur
´ ecriture
doit op´erer une coercition (transtypage ou casting) du type Objectvers la classe que l’on veut restituer
ObjectInputStream s =
new ObjectInputStream(new FileInputStream("toto"));
String chaine = (String)s.readObject();
Date date = (Date)s.readObject();
Un exemple
Unflux peut aussi ˆetre associ´e `a une connexion r´eseau et permettre d’envoyer des objets s´erialisables au travers tu r´eseau (chapitre 8)
Le programme exemple suivant connecte un flux d’entr´ee `a une URL (vue comme un fichier)
Il transforme ce flux d’octets en un flux de caract`eres et le place dans un tampon
Les lignes successivement lues en entr´ee sont copi´ees sur la sortie standard (jusqu’`a ce que readLineretourne null)
Un exemple
1 i m p o r t j a v a . net .*;
2 i m p o r t j a v a . io .*;
3 c l a s s U R L R e a d e r {
4 p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) 5 t h r o w s M a l f o r m e d U R L E x c e p t i o n , I O E x c e p t i o n { 6 URL url = new URL ( " h t t p :// k u n d e r a / i n d e x . h t m l " ) ; 7 B u f f e r e d R e a d e r in =
8 new B u f f e r e d R e a d e r ( 9 new I n p u t S t r e a m R e a d e r ( 10 url . o p e n S t r e a m () ) ) ; 11 S t r i n g l i g n e ;
12 w h i l e (( l i g n e = in . r e a d L i n e () ) != n u l l) 13 S y s t e m . out . p r i n t l n ( l i g n e ) ;
14 in . c l o s e () ;
15 }
16 }
Pour continuer...
Comment se comporte le m´ecanisme de s´erialisation vis `a vis de l’h´eritage ?
Comment sp´ecialiser ou modifier la s´erialisation ?
La classe Hashtable permet de stocker des valeurs en les associant `a des identificateurs uniques calcul´es `a partir des cl´es :
Les cl´es et valeurs ne doivent pas poss`eder la valeur null, mais en revanche peuvent ˆetre des objets de n’importe quel type
⇒s´erialiser le hastable pour g´erer un fichier de type base de donn´ees pouvant contenir n’importe quel type d’objet Java.
ComparaisonHashtableetHashmap, solutions ?
Comment se pr´eserver des acc`es concurrents sur les fichiers ?
Java nio
le package java.nioest propos´e depuis la version 1.4 de Java ;
nio = new IO (nouvelles E/S) ;
Propose des E/S non bloquantes et s´electionnables A l’origine un thread s’occupe d’une E/S`
Avec nio un thread peut prendre en charge plusieurs canaux d’E/S et tester la disponibilit´e de donn´ees (comme en C) Permet l’abandon et l’interruption des E/S donc de reveiller ou stopper un thread bloqu´e sur une E/S
Le mod` ele d’E/S de nio
Le mod`eles d’E/S du package nio est construit autour du concept de buffer;
Les buffer de nio sont des tableaux am´elior´es destin´es `a la communication ;
nio propose la notion de buffer directs : la m´emoire associ´ee r´eside hors de la machine virtuelle Java c`ad directement dans le syst`eme d’exploitation ;
nio propose deux caract´eristiques g´en´eriques li´ees aux fichiers : le mappage en m´emoire et le verouillage ;
Les fichier mapp´es se maniuplent comme si ils ´etaient r´esident en permanence en m´emoire ;
Le verouillage s’articule autout des verrous partag´es ou exclusifs sur des zones de fichiers.
Le mod` ele d’E/S de nio
Le package nio propose la notion de canal (subsititu´ee `a celle de flux) ;
D´efinition :
Un canal est un terminal de comminucation semblable aux flux mais plus abstrait dans le sens ou l’interface ´el´ementaire des canaux ne pr´ecise rien quant aux communications mais d´efinit les m´ethodesisOpen()et close().
Les impl´ementation des canaux d´edi´ees aux fichiers, sockets ou `a des p´eriph´eriques quelconques ajoutent leurs propres m´ethodes ;
nio propose les canaux princpaux suivant : FileChannel, Pipe.SinkChannel,Pipe.SourceChanel,SocketChannel, ServerSocketChaneletc.
Canaux fichiers
Le canal FileChannel est l’´equivalent de RandomAccessFile;
UnFileChannel est construit `a partir d’un
FileInputStream, d’unFileOutputStream ou d’un RandomAccessFile;
1 F i l e C h a n n e l r e a d O n l y f s = new F i l e I n p u t S t r e a m ( " fic . txt " ) . g e t C h a n n e l () ; 2 F i l e C h a n n e l r e a d W r i t e f c = new R a n d o m A c c e s s F i l e ( " fic . txt " , " rw " ) . g e t C h a n n e l
() ;
Un canal a un statut ouvert `a sa cr´eation ;
Canaux fichiers
L’utilisation d’un FileChannel se fait `a travers un buffer de type ByteBuffer;
1 try {
2 R e a d a b l e B y t e C h a n n e l c h a n n e l = new F i l e I n p u t S t r e a m ( " i n f i l e " ) . g e t C h a n n e l () ;
3 // C r e a t e a d i r e c t B y t e B u f f e r
4 B y t e B u f f e r buf = B y t e B u f f e r . a l l o c a t e D i r e c t ( 1 0 ) ;
5 int n u m R e a d = 0;
6 w h i l e ( n u m R e a d >= 0) {
7 // r e a d () p l a c e s r e a d b y t e s at the b u f f e r ’ s p o s i t i o n so the 8 // p o s i t i o n s h o u l d a l w a y s be p r o p e r l y set b e f o r e c a l l i n g r e a d
()
9 // T h i s m e t h o d s e t s the p o s i t i o n to 0
10 buf . r e w i n d () ;
11 // R e a d b y t e s f r o m the c h a n n e l 12 n u m R e a d = c h a n n e l . r e a d ( buf ) ;
13 // The r e a d () m e t h o d a l s o m o v e s the p o s i t i o n so in o r d e r to 14 // r e a d the new bytes , the b u f f e r ’ s p o s i t i o n m u s t be set b a c k
to 0
15 buf . r e w i n d () ;
16 // R e a d b y t e s f r o m B y t e B u f f e r
17 for (int i =0; i < n u m R e a d ; i ++) {
18 b y t e b = buf . get () ;
19 }
20 }
21 } c a t c h ( E x c e p t i o n e ) {
22 }
Verouillage
Les FileChannel supportent les verrous exclusifs ou partag´e sur des zones de fichiers
Les verrous sont g´er´es par la m´ethodelock()
1 F i l e L o c k v e r r o u F i c h i e r = c a n a l f . l o c k () ;
2 int d e b u t = 0;
3 int l o n g u e u r = c a n a l f 2 . s i z e () ;
4 F i l e L o c k v e r r o u L e c t u r e = c a n a l f 2 . l o c k ( d´ebut , l o n g u e u r ,t r u e) ;
Les verrous peuvent ˆetre patag´es ou exclusifs :
un verrou exclusif empˆeche quiconque d’obtenir un verrou sur le fichier ou sur une zone ;
un verrou partag´e permet `a d’autres d’acqu´erir des verrous partag´es mais non des verrous exclusif : lorqu’on ´ecrit, on interdit toutes les ´ecritures. Lorsqu’on lit, on interdit les
´
ecritures concurrentes, les lectures concurrentes restent possibles.
Verouillage
La m´ethode lock()permet d’obetnir un verrou exclusif ; La seconde forme (avec param`etres) permet d’indiquer une longueur et un drapeau indiquant si le verrou est partag´e ou exclusif ;
L’objet retourn´e par la m´ethode (fileLock) sert ensuite `a relacher le verrou au moyen de la m´ethoderelease().
Tr`es utile pour des interactions lecteurs r´edacteurs.
Verouillage
1 p u b l i c c l a s s l o c k {
2 p u b l i c s t a t i c v o i d m a i n ( S t r i n g arg []) {
3 try {
4 // Get a f i l e c h a n n e l for the f i l e 5 F i l e f i l e = new F i l e ( " l o c k . j a v a " ) ;
6 F i l e C h a n n e l c h a n n e l = new R a n d o m A c c e s s F i l e ( file , " rw " ) . g e t C h a n n e l () ; 7
8 // Use the f i l e c h a n n e l to c r e a t e a l o c k on the f i l e . 9 // T h i s m e t h o d b l o c k s u n t i l it can r e t r i e v e the l o c k . 10 F i l e L o c k l o c k = c h a n n e l . l o c k () ;
11
12 // Try a c q u i r i n g the l o c k w i t h o u t b l o c k i n g . T h i s m e t h o d r e t u r n s 13 // n u l l or t h r o w s an e x c e p t i o n if the f i l e is a l r e a d y l o c k e d .
14 try {
15 l o c k = c h a n n e l . t r y L o c k () ;
16 } c a t c h ( O v e r l a p p i n g F i l e L o c k E x c e p t i o n e ) {
17 // F i l e is a l r e a d y l o c k e d in t h i s t h r e a d or v i r t u a l m a c h i n e
18 }
19
20 R e a d e r r e a d e r = new I n p u t S t r e a m R e a d e r ( S y s t e m . in ) ; 21 B u f f e r e d R e a d e r i n p u t = new B u f f e r e d R e a d e r ( r e a d e r ) ; 22 S y s t e m . out . p r i n t ( " A p p u y e z sur E n t r e e " ) ;
23 S t r i n g p r e n o m = i n p u t . r e a d L i n e () ; 24 // R e l e a s e the l o c k
25 l o c k . r e l e a s e () ; 26
27 // C l o s e the f i l e
28 c h a n n e l . c l o s e () ; 29 } c a t c h ( E x c e p t i o n e ) {
30 }