Les entrées-sorties
Transcription
Les entrées-sorties
Les entrées-sorties Les pricipales classes du paquetage java.io ByteArrayInputStream FileInputStream BufferedInputStream FilterInputStream PushbackInputStream PipedInputStream LineNumberInputStream InputStream FileDescriptor File SequenceInputStream StringBufferInputStream StreamTokenizer DataInputStream DataInput Object RandomAccesFile DataOutput ByteArrayOutputStream DataOutputStream FileOutputStream OutputStream FilenameFilter FilterOutputStream BufferedOutputStream PipedOutputStream PrintStream Benoît Charroux - Les entrées - sorties - septembre 07 - 2 La classe abstraite InputStream • les méthodes read se bloquent tant que l’entrée n’est pas disponible ; • toutes les méthodes lancent IOExeption. Lit un octet (0, …, 255) Lit buf.length octets au maximum, retourne le nombre d’octets lus ou -1 si la fin du flot est atteinte. InputStream InputStream() abstract int read() Lit vers un sous tableau commençant à offset, len octets au maximum Saute count octets ou se positionne à la fin si elle est atteinte, retourne le nombre d’octets sautés int read( byte[] buf ) int read( byte[] buf, int offset, int len ) long skip( long count ) public int available() void close() Retourne le nombre d’octets pouvant être lus sans blocage Ferme un flot et libère la ressource associée Benoît Charroux - Les entrées - sorties - septembre 07 - 3 La classe abstraite InputStream • La classe java.lang.System offre un accès à : • l’entrée standard System.in ; • la sortie standard System.out ; • la sortie d’erreur standard System.err. try{ int i = Systen.in.read() ; byte b = (byte)i ; int nbOk = System.in.available() ; // nombre d’octets disponibles if( nbOk > 0 ){ byte [] données = new byte[ nbOk ] ; System.in.read( données ) ; } catch( IOException e ) { System.out.println( "Exception: " + e ) ; } Benoît Charroux - Les entrées - sorties - septembre 07 - 4 La classe abstraite OutputStream • les méthodes write se bloquent tant que l’écriture n’a pas été réalisée ; • toutes les méthodes lancent IOExeption. Écrit l’octet de poids faible de l’entier passé en paramètre Écrit un tableau d’octets OutputStream OutStream() abstract void write( int i ) Écrit au plus buf.length octets, ou au moins len octets du tableau buf void write( byte[] buf ) void write( byte[] buf, int offset, int len ) void flush() void close() Vide le flot de sortie Ferme un flot et libère la ressource associée Benoît Charroux - Les entrées - sorties - septembre 07 - 5 La classe DataInputStream • Comment lire des chaînes de caractères et obtenir des types de bases de java ? DataInputStream DataInputStream( InputStream in ) Lit dans un entier boolean readInt() … Benoît Charroux - Les entrées - sorties - septembre 07 - 6 La classe DataOutputStream • Comment écrire des données d’un type de base dans un flot ? Écrit un booléen DataOutputStream DataOutputStream( OutputStream out ) void writeBoolean( boolean b ) void writeChar() Écrit un caractère ... int size() Retourne le nombre de bytes écrit dans le flot • Toutes les méthodes lancent IOExeption. Benoît Charroux - Les entrées - sorties - septembre 07 - 7 La gestion des fichiers • Les classes FileInputStream et FileOutputStream permettent de lire et d’écrire dans des fichiers : FileInputStream fichier = new FileInputStream( "bidon" ) ; tailleFichier = fichier.available() ; // récupère la taille du fichier byte []contenuFichier = new byte[ tailleFichier ] ; // alloue à la bonne taille for( int i=0; i<tailleFichier; i++ ){ contenuFichier[ i ] = (byte)fichier.read() ; } fichier.close() ; Benoît Charroux - Les entrées - sorties - septembre 07 - 8 Les entrées / sorties bufferisées (1/2) • Ces classes utilisent un buffer pour réduire le nombre de lecture et d’écriture réellement effectuées dans le flux ; • ces classes sont souvent utilisées avec des fichiers : OutputStream FichierBufferisée( String nom ) throws IOException{ OutputStream out = new FileOutputStream( nom ) ; return new BufferedOutputStream( out ) ; // buffer de 512 bytes } • On peut préciser la taille du buffer dans le constructeur : BufferedInputStream( InputStream in, int size) Benoît Charroux - Les entrées - sorties - septembre 07 - 9 Les entrées / sorties bufferisées (2/2) • Exemple de la lecture d’un entier au clavier : BufferedReader buf = new BufferedReader( new InputStreamReader(System.in) ) ; try{ int i = Integer.parseInt( buf.readLine() ) ; } catch( NumberFormatException e ){ } • Exemple de la lecture ligne par ligne d’un fichier : BufferedReader in = new BufferedReader( new FileReader( "bidon.txt" ) ); String line ; while( (line=in.readLine()) != null ){ System.out.println( line ) ; } in.close() ; Benoît Charroux - Les entrées - sorties - septembre 07 - 10 L’accès au système de fichiers La classe File • La classe File est une représentation abstraite du système de gestion de fichiers. • Exemple de la création d'un répertoire dans le répertoire système TMP : Map<String,String> systemEnvironment = System.getenv(); String tmp = systemEnvironment.get( "TMP" ); tmp = tmp + "\\monRepertoire"; tmp = tmp.replace('\\', '/'); // pour former une URI tmp = "file:///" + tmp; // pour former une URI URI projectLocation = new URI(tmp); File projectDirectory = new File( projectLocation ); projectDirectory.mkdir(); Benoît Charroux - Les entrées - sorties - septembre 07 - 12 Les « Channels » L'interface Channel • Un Channel est une connexion vers une entrée-sortie : • qui traite toutes les entrées-sorties de façon unifiées (fichier, réseau...) ; • qui peut-être utilisé par plusieurs Threads concurrents. • Récupérer un Channel à partir d'un fichier : URI dataSourceIdentifier = new URI( ... ); File file = new File( dataSourceIdentifier ); FileInputStream fileInputStream = new FileInputStream( file ); FileChannel fileChannel = fileInputStream.getChannel(); Benoît Charroux - Les entrées - sorties - septembre 07 - 14 Utiliser un Channel pour optimiser les accès I/O (1/2) • La technique : • obtenir un channel sur un fichier par exemple ; • demander au système de réserver un buffer qui fait des opérations d'entrées-sorties "natives” (qui n'utilise aucun buffer intermédiaire) ; • transférer des données du channel vers le buffer natif ; • manipuler le buffer natif. Benoît Charroux - Les entrées - sorties - septembre 07 - 15 Utiliser un Channel pour optimiser les accès I/O (1/2) • Le programme : ... long fileLength = channel.size(); // TO DO : vérifier que fileLength ne dépasse pas la taille d'un entier ByteBuffer nativeBuffer = ByteBuffer.allocateDirect( (int)fileLength ); long filePosition = ... int bytesReaden = channel.read( nativeBuffer, filePosition ); if( bytesReaden != -1 ){ byte[] buffer = new Buffer[ bytesReaden ]; nativeBuffer.get( buffer, 0, bytesReaden ); // extraire du buffer natif vers un buffer classique } Benoît Charroux - Les entrées - sorties - septembre 07 - 16 La sérialisation d’objets La sérialisation d’objets Intérêt de la sérialisation : • les applications réparties sur plusieurs machines ont besoin de s’échanger des objets ; • l’état des objets d’une application (valeur instantanée des attributs des objets) doit pouvoir être sauvegardé (stockage sur disque par exemple) et restitué. L’API de sérialisation : ObjectOutputStream( OutputStream ) ObjectInputStream( InputStream ) writeObject( Object ) Object readObject() sérialiser désérialiser Champs sérialiasables de l’objet ObjectStreamClass Champs sérialisables des super-classes nomDeLaClasse serialVersionUID Benoît Charroux - Les entrées - sorties - septembre 07 - 18 La sérialisation d’objets • tous les types de bases ainsi que la plupart des objets des librairies peuvent être sérialisés ; • un champs statique ne sera pas sérialisé ; • pour empêcher qu’un champs soit sérialisé on peut le déclarer avec le mot clef transient ; • pour indiquer qu’une classe peut être sérialisée, elle doit implémenter l’interface java.io.Serializable : class Bidon implements java.io.Serializable { // … } • pour sérialiser un objet pointant sur des ressources système (un descripteur de fichier par exemple), il est possible de surcharger les méthodes writeObject et readObject (pour fermer et ouvrir correctement les fichiers) ; • pour désérialiser un objet (readObject), il faut que la classe correspondante puisse être chargée. Benoît Charroux - Les entrées - sorties - septembre 07 - 19 Exemple de sérialisation dans un fichier FileOutputStream monFichier = new FileOutputStream( "fichier.tmp" ) ; // diriger le flux de sérialisation vers un fichier ObjectOutputStream fluxObjet = new ObjectOutputStream( monFichier ) ; fluxObjet.writeObject( "aujourd’hui" ) ; // sérialise une chaîne fluxObjet.writeObject( new Date() ) ; // sérialise une date fluxObjet.flush() ; // vide le flux fluxObjet.close() ; monFichier.close() ; Benoît Charroux - Les entrées - sorties - septembre 07 - 20 La désérialisation à partir d’un fichier FileInputStream monFichier = new FileInputStream( "fichier.tmp" ) ; // diriger le fichier vers le flux de désérialisation ObjectInputStream fluxObjet = new ObjectInputStream( monFichier ) ; String chaine = (String) fluxObjet .readObject() ; // désérialise la chaîne Date date = (Date) fluxObjet .readObject() ; // désérialise une date Benoît Charroux - Les entrées - sorties - septembre 07 - 21