char
sont en fait des entiers
représentables sur seize bits (de 0 à 216−1). Ces entiers sont en
quelque sorte les « codes » des caractères selon une convention
mondiale.Le « -1
» que peut renvoyer read n'est pas un
caractère, il indique au contraire qu'il n'y a plus de caractères.
La méthode read renvoie un entier car c'est un bon moyen de pouvoir renvoyer à la fois les 216 caractères possibles, et « autre chose » dans le cas où le flux est fini.
static void dump(Reader fr) throws IOException { // Hum numéro un int c ; while ((c = fr.read()) != -1) { // Hum numéro deux System.out.print((char)c) ; // Hum numéro trois } } |
IOException
car cette méthode contient un appel à
fr.read
. Il faut déclarer ce fait (noter bien
throws
avec un « s »).
int c ; c = fr.read() ; while (c != -1) { System.out.print((char)c) ; // Hum numéro trois c = fr.read() ; } } |
x = y = z = 0 ; // À comprendre comme x = (y = (z = 0)) ; |
c
contient un int
. Si on le passe
directement à la méthode print
(de l'objet
System.out
), alors on affiche cet entier.
Il faut bien dire que l'entier est ici vu comme un caractère, d'ou la
construction (char)c
que l'on appelle un type cast
(conversion de type).
On pourrait donc penser qu'il existe divers consructeurs de la classe
Reader
prenant en argument une chaîne, un nom de fichier
etc. En fait il n'en est rien, la classe Reader
n'a pas de
constructeur. Elle sert non pas à créer des objets mais à créer
d'autre classes par héritage.
Des sous-classes sont définies comme héritant de Reader
(et donc, entre autres, comme possédant une méthode read).
Pour ce qui nous concerne, cela revient un peu à considérer une
interface Reader
et diverses classes
FileReader
, StringReader
etc. qui
l'implémentent (mais le mécanisme est en fait plus puissant).
À titre d'exemple voici un petit programme qui affiche le contenu d'un fichier dont le nom est donné comme premier argument de la ligne de commande :
import java.io.* ; class Cat { static void dump(Reader fr) throws IOException { // Hum numéro un int c ; while ((c = fr.read()) != -1) { // Hum numéro deux System.out.print((char)c) ; // Hum numéro trois } } public static void main(String [] argv) { try { Reader fr = new FileReader(argv[0]) ; dump(fr) ; fr.close() ; } catch ( IOException e ) { System.err.println("Erreur d'entrée sortie : " + e.getMessage()) ; } catch (ArrayIndexOutOfBoundsException e) { System.err.println ("Mauvais nombre d'arguments"); } } } |
Notez d'abord le import java.io.* ;
. Cette incantation est
nécessaire pour accéder à la classe Reader
.
Notez que le flux est crée comme un FileReader
et rangé
dans une variable de type Reader
. C'est possible car, par
héritage, un FileReader
est au moins un
Reader
(ici, il a les méthodes qui nous intéressent avec
les bonnes signatures).
Notez aussi la fermeture de fr
(par la méthode
close). Cela permet de dire au système Java de récupérer les
ressources mobilisées lors de la création du flux, et les rend libres
pour la création de nouveaux flux (ici c'est un peu inutile).
Il faut en effet savoir qu'un programme donné (Unix, ici la machine
Java) ne peut posséder qu'un nombre limité de fichiers ouverts
simultanéement.