Writer
et
OutputStream
, que nous venons de voir dans la section précédente, sont donc associées les classes
Reader
et
InputStream
respectivement.
Reader
est une classe abstraite, étendue par
CharArrayReader
,
StringReader
et
FileReader
, indirectement. Ces trois classes permettent de lire des flux de caractères en provenance de tableaux de
char
, de chaînes de caractères, ou de fichiers.
La classe
Reader
expose plusieurs versions d'une méthode
read()
, dont le fonctionnement est constant. Cette méthode permet de lire des caractères, un par un, ou en les stockant dans un tableau. Toutes ces versions de
read()
retournent un
int
. Ce nombre correspond au nombre de caractères effectivement lus sur le flux. Si ce nombre est égal à -1, c'est que la fin du flux a été rencontrée. Voyons ceci sur un exemple.
Notons qu'un appel à
read()
peut
bloquer
, c'est-à-dire, ne retourner de valeur qu'au bout d'un certain temps, durant lequel le flux est en attente de l'arrivée de nouveaux caractères.
Notons enfin qu'il peut arriver que le nombre de caractères lus soit plus petit que la taille du buffer, sans pour autant que la fin du flux soit atteinte.
Exemple 121. Utilisation de
FileReader
public static void main(String[] args) { // déclaration de notre FileReader à l'exétieur des // blocs try {} catch {} FileReader fr = null ; try { // ouverture du flux de lecture // peut jeter une FileNotFoundException fr = new FileReader("tmp/bonjour.text") ; // définition du buffer : un tableau de char int bufferSize = 1024 ; char [] buffer = new char[bufferSize] ; // définitions de variables pour suivre notre // lecture int n = 0 ; int total = 0 ; int loops = 0 ; do { // remplissage du buffer // n contient le nombre de caractères effectivement lus n = fr.read(buffer) ; total += n ; loops++ ; // si le nombre lu est -1, // c'est que l'on a atteint la fin du flux } while (n != -1) ; // quelques informations sur la lecture System.out.println( "Nombre de caractères lus au total = " + total + " en " + loops + " boucles.") ; } catch (FileNotFoundException e) { // gestion de l'erreur } catch (IOException e) { // gestion de l'erreur } finally { // pattern de fermeture d'un flux if (fr != null) { try { fr.close() ; } catch (IOException e) { // gestion de l'erreur } } } }
FileReader
expose également deux méthodes utilitaires.
skip(long n)
: permet de sauter la lecture du nombre de caractères passés en paramètre. Cette méthode retourne le nombre de caractères effectivement sautés.
ready()
: retourne
true
si le flux possède des caractères prêts à être lus. Un appel à
read()
après un appel à
ready()
qui a retourné
true
ne bloquera donc pas.
BufferedReader
. En plus de sa fonctionnalité de bufferisation, elle expose une méthode très utile :
readLine()
, qui retourne une chaîne de caractères (
String
) contenant la ligne lue.
LineNumberReader()
, qui permet de récupérer le numéro de ligne. Voyons ceci sur un exemple.
Exemple 122. Lecture d'un fichier ligne par ligne :
LineNumberReader
// le début du code est inchangé fr = new FileReader("tmp/bonjour.text") ; // ouverture d'un flux sur le flux de lecture du fichier LineNumberReader lnr = new LineNumberReader(fr) ; String line = null ; do { // lecture du numéro de la ligne courante int number = lnr.getLineNumber() ; // lecture d'une ligne line = lnr.readLine() ; // affichage de cette ligne, et de son numéro if (line != null) { System.out.println("[" + number + "] : " + line) ; } } while (line != null) ; // la fin du code est inchangée
OutputStream
est la classe
InputStream
. Cette classe abstraite est la base des classes de lecture des flux d'octets.
Elle est étendue par
FileInputStream
pour la lecture dans des fichiers ;
ByteArrayInputStream
pour la lecture dans des tableaux d'octets ;
DataInputStream
pour la lecture des types primitifs Java ;
ObjectInputStream
pour la lecture des objets sérialisés.
read()
retourne le nombre d'octets effectifs qui ont été lus. Lorsque ce nombre est -1, la fin du flux a été atteinte.
La classe
InputStream
expose les méthodes suivantes.
read()
,
read(byte[] buf)
et
read(byte[] buf, int offset, int length)
: ces méthodes permettent de lire les octets dans un tableau. Elles retournent toutes le nombre d'octets effectivement lus.
skip(long n)
: saute le nombre d'octets passé en paramètre dans le flux de lecture.
reset()
: réinitialise la lecture de ce flux.
available()
: retourne le nombre d'octets disponibles dans un
int
. Ce nombre d'octets peut être lu, ou sauté. La lecture qui suit ne bloquera pas, tant que ce nombre ne sera pas dépassé.
Exemple 123. Utilisation de
FileInputStream
public static void main(String[] args) { // déclaration de notre InputStream à l'exétieur des // blocs try {} catch {} InputStream is = null ; try { // ouverture du flux d'entrée sur un fichier // peut jeter une FileNotFoundException is = new FileInputStream(fichier) ; // définition du buffer : un tableau d'octets int bufferSize = 1024 ; byte [] buffer = new byte[bufferSize] ; // définitions de variables pour suivre notre // lecture int n = 0 ; int total = 0 ; int loops = 0 ; do { // remplissage du buffer // n contient le nombre d'octets effectivement lus n = is.read(buffer) ; total += n ; loops++ ; // si le nombre lu est -1, // c'est que l'on a atteint la fin du flux } while (n != -1) ; // quelques informations sur la lecture System.out.println( "Nombre d'octets lus au total = " + total + " en " + loops + " boucles.") ; } catch (FileNotFoundException e) { // gestion de l'erreur } catch (IOException e) { // gestion de l'erreur } finally { // pattern de fermeture d'un flux if (fr != null) { try { fr.close() ; } catch (IOException e) { // gestion de l'erreur } } } }
DataInputStream
expose un jeu de méthodes qui permet de lire les types primitifs Java directement dans des flux binaires :
readInt()
,
readLong()
, etc...
Cette classe expose de plus une méthode
readFully(byte[] buf)
, implémentation de la même méthode de l'interface
DataInput
. Le contrat de cette méthode est différent de celui de la méthode
read(byte[] buff)
exposée entre autres par la classe
InputStream
. La différence entre les deux est subtile, et mérite d'être expliquée ici.
La méthode
read(byte [] buff)
lit un certain nombre d'octets, et les range dans le tableau passé en paramètre. Lorsqu'elle décide de rendre la main, le nombre d'octets effectivement écrit est retourné par cette méthode. Rien n'impose que ce nombre soit égal à la taille du tableau, il arrive souvent que ce ne soit pas le cas.
La méthode
readFully(byte[] buff)
, elle, garantit que le tableau retourné est bien rempli. Notons que cette méthode ne retourne rien. Si la fin du flux est rencontrée durant la lecture, alors une exception de type
EOFException
est jetée, et le tableau passé en paramètre est partiellement rempli, sans que l'on puisse savoir de combien de cases. Cette méthode doit donc être utilisée avec précautions.
String
StringBuffer
et
StringBuilder