t
t
t
t
t t   11) Le système d’E/S de Java
tttt
t
carrea) Préface carreb) Avant-propos carre1) Introduction sur les &laqo; objets » carre2) Tout est &laqo; objet » carre3) Contrôle du flux du programme carre4) Initialization & Cleanup carre5) Cacher l'implémentation carre6) Réutiliser les classes carre7) Polymorphisme carre8) Interfaces & classes internes carre9) Stockage des objets carre10) Error Handling with Exceptions 11) Le système d’E/S de Java carre12) Identification dynamique de type carre13) Création de fenêtres & d'Applets carre14) Les &laqo; Threads » multiples carre15) Informatique distribuée carreA) Passage et retour d'objets carreB) L'Interface Java Natif (JNI) carreC) Conseils pour une programation stylée en Java carreD) Resources
Texte original t Traducteur : Armel Fortun
t
t
///
Ce chapitre contient 10 pages
1 2 3 4 5 6 7 8 9 10
\\\
t t t
t t t
t
t t t
Here is a table that shows the correspondence between the sources and sinks of information (that is, where the data physically comes from or goes to) in the two hierarchies.
t Voici un tableau qui montre les correspondances entre les sources et les réceptacles d'informations (c'est à dire, d'où les données physiques viennent ou vont) dans les deux hiérarchies.
t t t
Sources & Sinks:
Java 1.0 class
Corresponding Java 1.1 class
InputStream
Reader
converter: InputStreamReader
OutputStream
Writer
converter: OutputStreamWriter
FileInputStream
FileReader
FileOutputStream
FileWriter
StringBufferInputStream
StringReader
(no corresponding class)
StringWriter
ByteArrayInputStream
CharArrayReader
ByteArrayOutputStream
CharArrayWriter
PipedInputStream
PipedReader
PipedOutputStream
PipedWriter
t
Sources & Récipients: Classe Java 1.0 Classe Java 1.1 correspondante
InputStream Reader convertisseur : InputStreamReader
OutputStream Writer convertisseur : OutputStreamWriter
FileInputStream FileReader
FileOutputStream FileWriter
StringBufferInputStream StringReader
(pas de classe correspondante) StringWriter
ByteArrayInputStream CharArrayReader
ByteArrayOutputStream CharArrayWriter
PipedInputStream PipedReader
PipedOutputStream PipedWriter
t t t
In general, you’ll find that the interfaces for the two different hierarchies are similar if not identical.
t En général, vous constaterez que les interfaces pour les deux différentes hiérarchies sont semblables sinon identiques.
t t t

Modifying stream behavior

t

Modifier le comportement du flux

t t t
For InputStreams and OutputStreams, streams were adapted for particular needs using “decorator” subclasses of FilterInputStream and FilterOutputStream. The Reader and Writer class hierarchies continue the use of this idea—but not exactly.
t Pour les InputStreams et OutputStreams, les flux sont adaptés à des usages particuliers en utilisant des sous-classes « décoratives » de FilterInputStream et FilterOutputStream. La hiérarchie de classe Reader et Writer poursuit l'usage de ce concept — mais pas exactement.
t t t
In the following table, the correspondence is a rougher approximation than in the previous table. The difference is because of the class organization: while BufferedOutputStream is a subclass of FilterOutputStream, BufferedWriter is not a subclass of FilterWriter (which, even though it is abstract, has no subclasses and so appears to have been put in either as a placeholder or simply so you wouldn’t wonder where it was). However, the interfaces to the classes are quite a close match.
t Dans le tableau suivant, la correspondance est une approximation plus grossière que dans la table précédente. La différence est engendrée par l'organisation de la classe : Quand BufferedOutputStream est une sous-classe de FilterOutputStream, BufferedWriter n'est pas une sous-classe de FilterWriter (laquelle, bien qu'elle soit abstract, n'a pas de sous-classe et donc semble avoir été mise dedans de manière à réserver la place ou simplement de manière à ce que vous ne sachiez pas où elle se trouve). Cependant, les interfaces pour les classes est plutôt un combat terminé.
t t t
Filters:
Java 1.0 class
Corresponding Java 1.1 class
FilterInputStream
FilterReader
FilterOutputStream
FilterWriter (abstract class with no subclasses)
BufferedInputStream
BufferedReader
(also has readLine( ))
BufferedOutputStream
BufferedWriter
DataInputStream
Use DataInputStream
(Except when you need to use readLine( ), when you should use a BufferedReader)
PrintStream
PrintWriter
LineNumberInputStream
LineNumberReader
StreamTokenizer
StreamTokenizer
(use constructor that takes a Reader instead)
PushBackInputStream
PushBackReader
t
Filtres : classe Java 1.0 Classe correspondante en Java 1.1
FilterInputStream FilterReader
FilterOutputStream FilterWriter (classe abstract sans sous-classe)
BufferedInputStream BufferedReader (a aussi readLine())
BufferedOutputStream BufferedWriter
DataInputStream Utilise DataInputStream (sauf quand vous voulez utiliser readLine(), alors vous devez utiliser un BufferedReader)
PrintStream PrintWriter
LineNumberInputStream LineNumberReader
StreamTokenizer StreamTokenizer (utilise un constructeur qui prend un Reader à la place)
PushBackInputStream PushBackReader
t t t
There’s one direction that’s quite clear: Whenever you want to use readLine( ), you shouldn’t do it with a DataInputStream any more (this is met with a deprecation message at compile-time), but instead use a BufferedReader. Other than this, DataInputStream is still a “preferred” member of the I/O library.
t Il y a un sens qui est tout à fait clair : Chaque fois que vous voulez utiliser readLine(), vous ne devrez plus le faire avec un DataInputStream (ceci recevant un message de depréciation au moment de la compilation), mais utiliser à la place un BufferedReader. À part cela, DataInputStream est pourtant l'élément « préféré » de la bibliothèque d'E/S.
t t t
To make the transition to using a PrintWriter easier, it has constructors that take any OutputStream object, as well as Writer objects. However, PrintWriter has no more support for formatting than PrintStream does; the interfaces are virtually the same.
t Pour faire la transition vers l'emploi facile d'un PrintWriter, il possède des constructeurs qui prennent n'importe quel objet OutputStream, aussi bien que des objets Writer. Cependant, PrintWriter n'a pas plus de support pour formater comme le faisait PrintStream ; les interfaces sont de fait les mêmes.
t t t
The PrintWriter constructor also has an option to perform automatic flushing, which happens after every println( ) if the constructor flag is set.
t Le constructeur de PrintWriter possède également une option pour effectuer le vidage automatique de la mémoire [automatic flushing], lequel se produit après chaque println() si le drapeau du constructeur est levé dans ce sens.
t t t

Unchanged Classes

t

Les classes inchangées

t t t
Some classes were left unchanged between Java 1.0 and Java 1.1: t Certaines classes ont été laissées inchangées entre Java 1.0 et Java 1.1 :
t t t

Java 1.0 classes without corresponding Java 1.1 classes
DataOutputStream
File
RandomAccessFile
SequenceInputStream
t
Les classes de Java 1.0 qui n'ont pas de classes correspondantes en Java 1.1
DataOutputStream
File
RandomAccessFile
SequenceInputStream
t t t
DataOutputStream, in particular, is used without change, so for storing and retrieving data in a transportable format you use the InputStream and OutputStream hierarchies.
t DataOutputStream, en particulier, est utilisé sans modification, donc pour stocker et retrouver des données dans un format transportable vous utiliserez les hiérarchies InputStream et OutputStream.
t t t

Off by itself:
RandomAccessFile

t

Et bien sûr : L'accès aléatoire aux fichiers (RandomAccessFile)

t t t
RandomAccessFile is used for files containing records of known size so that you can move from one record to another using seek( ), then read or change the records. The records don’t have to be the same size; you just have to be able to determine how big they are and where they are placed in the file.
t RandomAccessFile est employé pour les fichiers dont la taille de l'enregistrement est connue, de sorte que vous pouvez bouger d'un enregistrement à un autre en utilisant seek(), puis lire ou changer les enregistrements. Les enregistrements n'ont pas forcément la même taille ; vous devez seulement être capable de déterminer de quelle grandeur ils sont et où ils sont placés dans le fichier.
t t t
At first it’s a little bit hard to believe that RandomAccessFile is not part of the InputStream or OutputStream hierarchy. However, it has no association with those hierarchies other than that it happens to implement the DataInput and DataOutput interfaces (which are also implemented by DataInputStream and DataOutputStream). It doesn’t even use any of the functionality of the existing InputStream or OutputStream classes—it’s a completely separate class, written from scratch, with all of its own (mostly native) methods. The reason for this may be that RandomAccessFile has essentially different behavior than the other I/O types, since you can move forward and backward within a file. In any event, it stands alone, as a direct descendant of Object.
t D'abord il est un peu difficile de croire que RandomAccessFile ne fait pas partie de la hiérarchie d'InputStream ou d'OutputStream. Cependant, il n'y a pas d'association avec ces hiérarchies autre que quand il arrive de mettre en œuvre les interfaces DataInput et DataOutput (qui sont également mises en œuvre par DataInputStream et DataOutputStream). Elle n'utilise même pas la fonctionnalité des classes existantes InputStream et OutpuStream — il s'agit d'une classe complétement différente, écrite en partant de zéro, avec toutes ses propres méthodes (pour la plupart native). Une raison à cela pouvant être que RandomAccessFile a des comportements essentiellement différents des autres types d'E/S, dès qu'il est possible de se déplacer en avant et en arrière dans un fichier. De toute façon, elle reste seule, comme un descendant direct d'Object.
t t t
Essentially, a RandomAccessFile works like a DataInputStream pasted together with a DataOutputStream, along with the methods getFilePointer( ) to find out where you are in the file, seek( ) to move to a new point in the file, and length( ) to determine the maximum size of the file. In addition, the constructors require a second argument (identical to fopen( ) in C) indicating whether you are just randomly reading (“r”) or reading and writing (“rw”). There’s no support for write-only files, which could suggest that RandomAccessFile might have worked well if it were inherited from DataInputStream.
t Essentiellement, un RandomAccessFile fonctionne comme un DataInputStream collé ensemble avec un DataOutputStream, avec les méthodes getFilePointer() pour trouver où on se trouve dans le fichier, seek() pour se déplacer vers un nouvel emplacement dans le fichier, et length() pour déterminer la taille maximum du fichier. En complément, les constructeurs requièrent un deuxième argument (identique à fopen() en C) indiquant si vous effectuez de manière aléatoire une lecture (« r ») ou une lecture et écriture (« rw »). Il n'y a pas de ressource pour les fichiers en lecture seule, ce qui pourrait suggérer que RandomAccessFile aurait mieux fonctionné s'il se trouvait hérité de DataInputStream.
t t t
The seeking methods are available only in RandomAccessFile, which works for files only. BufferedInputStream does allow you to mark( ) a position (whose value is held in a single internal variable) and reset( ) to that position, but this is limited and not very useful.
t Les méthodes de recherche sont valables seulement dans RandomAccessFile, qui fonctionne seulement avec des fichiers. Le BufferedInputStream permet de marquer « mark() » une position (dont la valeur est tenue dans une seule variable interne) et d'annuler cette position « reset() », mais c'est limité et pas très pratique.
t t t

Typical uses of I/O streams

t

L'usage typique des flux d'E/S

t t t
Although you can combine the I/O stream classes in many different ways, you’ll probably just use a few combinations. The following example can be used as a basic reference; it shows the creation and use of typical I/O configurations. Note that each configuration begins with a commented number and title that corresponds to the heading for the appropriate explanation that follows in the text.
t Bien que pouvez combiner les classes de flux d'E/S de différentes manières, vous utiliserez probablement quelques combinaisons. L'exemple suivant pourra être employé comme une référence de base ; il montre la création et l'utilisation de configurations d'E/S typiques. Notez que chaque configuration commence par un commentaire avec numéro et titre qui correspondent aux titres des paragraphes suivant et fournissant l'explication approprié.
t t t
//: c11:IOStreamDemo.java // Typical I/O stream configurations. import java.io.*; public class IOStreamDemo { // Throw exceptions to console: public static void main(String[] args) throws IOException { // 1. Reading input by lines: BufferedReader in = new BufferedReader( new FileReader("IOStreamDemo.java")); String s, s2 = new String(); while((s = in.readLine())!= null) s2 += s + "\n"; in.close(); // 1b. Reading standard input: BufferedReader stdin = new BufferedReader( new InputStreamReader(System.in)); System.out.print("Enter a line:"); System.out.println(stdin.readLine()); // 2. Input from memory StringReader in2 = new StringReader(s2); int c; while((c = in2.read()) != -1) System.out.print((char)c); // 3. Formatted memory input try { DataInputStream in3 = new DataInputStream( new ByteArrayInputStream(s2.getBytes())); while(true) System.out.print((char)in3.readByte()); } catch(EOFException e) { System.err.println("End of stream"); } // 4. File output try { BufferedReader in4 = new BufferedReader( new StringReader(s2)); PrintWriter out1 = new PrintWriter( new BufferedWriter( new FileWriter("IODemo.out"))); int lineCount = 1; while((s = in4.readLine()) != null ) out1.println(lineCount++ + ": " + s); out1.close(); } catch(EOFException e) { System.err.println("End of stream"); } // 5. Storing & recovering data try { DataOutputStream out2 = new DataOutputStream( new BufferedOutputStream( new FileOutputStream("Data.txt"))); out2.writeDouble(3.14159); out2.writeChars("That was pi\n"); out2.writeBytes("That was pi\n"); out2.close(); DataInputStream in5 = new DataInputStream( new BufferedInputStream( new FileInputStream("Data.txt"))); BufferedReader in5br = new BufferedReader( new InputStreamReader(in5)); // Must use DataInputStream for data: System.out.println(in5.readDouble()); // Can now use the "proper" readLine(): System.out.println(in5br.readLine()); // But the line comes out funny. // The one created with writeBytes is OK: System.out.println(in5br.readLine()); } catch(EOFException e) { System.err.println("End of stream"); } // 6. Reading/writing random access files RandomAccessFile rf = new RandomAccessFile("rtest.dat", "rw"); for(int i = 0; i < 10; i++) rf.writeDouble(i*1.414); rf.close(); rf = new RandomAccessFile("rtest.dat", "rw"); rf.seek(5*8); rf.writeDouble(47.0001); rf.close(); rf = new RandomAccessFile("rtest.dat", "r"); for(int i = 0; i < 10; i++) System.out.println( "Value " + i + ": " + rf.readDouble()); rf.close(); } } ///:~ t
//: c11:IOStreamDemo.java
// Configurations typiques de flux d'E/S.
import java.io.*;

public class IOStreamDemo {
  // Lance les exeptions vers la console :
  public static void main(String[] args)
  throws IOException {
    // 1. Lecture d'entrée par lignes :
    BufferedReader in =      new BufferedReader(
        new FileReader("IOStreamDemo.java"));
    String s, s2 = new String();
    while((s = in.readLine())!= null)
      s2 += s + "\n";
    in.close();

    // 1b. Lecture d'entrée standard :
    BufferedReader stdin =      new BufferedReader(
        new InputStreamReader(System.in));      
    System.out.print("Enter a line:");
    System.out.println(stdin.readLine());

    // 2. Entrée depuis la mémoire
    StringReader in2 = new StringReader(s2);
    int c;
    while((c = in2.read()) != -1)
      System.out.print((char)c);

    // 3. Entrée de mémoire formattée
    try {
      DataInputStream in3 =        new DataInputStream(
          new ByteArrayInputStream(s2.getBytes()));
      while(true)
        System.out.print((char)in3.readByte());
    } catch(EOFException e) {
      System.err.println("End of stream");
    }

    // 4. Sortie de fichier
    try {
      BufferedReader in4 =        new BufferedReader(
          new StringReader(s2));
      PrintWriter out1 =        new PrintWriter(
          new BufferedWriter(
            new FileWriter("IODemo.out")));
      int lineCount = 1;
      while((s = in4.readLine()) != null )
        out1.println(lineCount++ + ": " + s);
      out1.close();
    } catch(EOFException e) {
      System.err.println("End of stream");
    }

    // 5. Stockage et recupération de donnée
     try {
      DataOutputStream out2 =        new DataOutputStream(
          new BufferedOutputStream(
            new FileOutputStream("Data.txt")));
      out2.writeDouble(3.14159);
      out2.writeChars("That was pi\n");
      out2.writeBytes("That was pi\n");
      out2.close();
      DataInputStream in5 =        new DataInputStream(
          new BufferedInputStream(
            new FileInputStream("Data.txt")));
      BufferedReader in5br =        new BufferedReader(
          new InputStreamReader(in5));
      // Doit utiliser DataInputStream pour des données :
      System.out.println(in5.readDouble());
      // Peut maintenant employer le readLine():
      System.out.println(in5br.readLine());
      // Mais la ligne ressort bizzarement.
      // Celle crée avec writeBytes est OK:
      System.out.println(in5br.readLine());
    } catch(EOFException e) {
      System.err.println("End of stream");
    }

    // 6. Lecture/écriture par accès aléatoire aux fichiers [Reading/writing random access files]
    RandomAccessFile rf =      new RandomAccessFile("rtest.dat", "rw");
    for(int i = 0; i < 10; i++)
      rf.writeDouble(i*1.414);
    rf.close();

    rf =      new RandomAccessFile("rtest.dat", "rw");
    rf.seek(5*8);
    rf.writeDouble(47.0001);
    rf.close();

    rf =      new RandomAccessFile("rtest.dat", "r");
    for(int i = 0; i < 10; i++)
      System.out.println(
        "Value " + i + ": " +
        rf.readDouble());
    rf.close();
  }
} ///:~
t t t
Here are the descriptions for the numbered sections of the program:
t Voici les descriptions pour les sections numérotées du programme :
t t t

Input streams

t

Flux d'Entrée

t t t
Parts 1 through 4 demonstrate the creation and use of input streams. Part 4 also shows the simple use of an output stream.
t La partie 1 à 4 démontre la création et l'utilisation des flux d'entrée. La partie 4 montre aussi l'emploi simple d'un flux de sortie.
t t t

1. Buffered input file

t

1. Entrée en tampon du fichier [Buffered input file]

t t t
To open a file for character input, you use a FileInputReader with a String or a File object as the file name. For speed, you’ll want that file to be buffered so you give the resulting reference to the constructor for a BufferedReader. Since BufferedReader also provides the readLine( ) method, this is your final object and the interface you read from. When you reach the end of the file, readLine( ) returns null so that is used to break out of the while loop.
t Afin d'ouvrir un fichier pour l'entrée de caractères, on utilise un FileInputReader avec un objet String ou File comme nom de fichier. Pour la vitesse, on désirera que le fichier soit mis en mémoire tampon alors on passera la référence résultante au constructeur à un BufferedReader. Puisque BufferedReader fournit aussi la méthode readLine( ), qui est notre objet final et l'interface depuis laquelle on lit. Quand on cherche la fin du fichier, readLine( ) renverra null qui sera utilisé pour sortir de la boucle while.
t t t
The String s2 is used to accumulate the entire contents of the file (including newlines that must be added since readLine( ) strips them off). s2 is then used in the later portions of this program. Finally, close( ) is called to close the file. Technically, close( ) will be called when finalize( ) runs, and this is supposed to happen (whether or not garbage collection occurs) as the program exits. However, this has been inconsistently implemented, so the only safe approach is to explicitly call close( ) for files.
t Le String s2 est utilisé pour accumuler le contenu entier du fichier (incluant les nouvelles lignes qui doivent être ajoutées puisque readLine( ) les enlève). s2 est ensuite employé dans la dernière partie de se programme. Enfin, close( ) est appelé pour fermer le fichier. Techniquement, close( ) sera appelé au lancement de finalize(), et ceci est supposé se produire (que le garbage collector se mette en route ou pas) lors de la fermeture du programme. Cependant, ceci a été inconséquemment implémenté, c'est pourquoi la seule approche sûre est d'appeler explicitement close( ) pour les fichiers.
t t t
Section 1b shows how you can wrap System.in for reading console input. System.in is a DataInputStream and BufferedReader needs a Reader argument, so InputStreamReader is brought in to perform the translation.
t La section 1b montre comment envelopper System.in afin de lire l'entrée sur la console. System.in est un DataInputStream et BufferedReader nécessite un argument Reader, voilà pourquoi InputStreamReader est introduit pour effectuer la traduction.
t t t

2. Input from memory

t

2. Entrée depuis la mémoire

t t t
This section takes the String s2 that now contains the entire contents of the file and uses it to create a StringReader. Then read( ) is used to read each character one at a time and send it out to the console. Note that read( ) returns the next byte as an int and thus it must be cast to a char to print properly.
t Cette partie prend le String s2 qui contient maintenant le contenu entier du fichier et l'utilise pour créer un StringReader. Puis read( ) est utilisé pour lire chaque caractère un par un et les envoie vers la console. Notez que read( ) renvoie le byte suivant sous la forme d'un int et pour cette raison il doit être convertit en char afin de s'afficher correctement.
t t t

3. Formatted memory input

t

3. Entrée de mémoire formatée

t t t
To read “formatted” data, you use a DataInputStream, which is a byte-oriented I/O class (rather than char oriented). Thus you must use all InputStream classes rather than Reader classes. Of course, you can read anything (such as a file) as bytes using InputStream classes, but here a String is used. To convert the String to an array of bytes, which is what is appropriate for a ByteArrayInputStream, String has a getBytes( ) method to do the job. At that point, you have an appropriate InputStream to hand to DataInputStream.
t Pour lire une donnée « formatée », vous utiliserez un DataInputStream, qui est une classe d'E/S orientée-byte (plutôt qu'orientée-char). Ainsi vous devrez utiliser toutes les classes InputStream plutôt que les classes Reader. Bien sur, vous pouvez lire n'importe quoi (du genre d'un fichier) comme des bytes en utilisant les classes InputStream, mais ici c'est un String qui est utilisé. Pour convertir le String en un tableau de bytes, ce qui est approprié pour un ByteArrayInputStream, String possède une méthode getBytes()pour faire le travail. A ce stade, vous avez un InputStream adéquat pour porter un DataInputStream.
t t t
If you read the characters from a DataInputStream one byte at a time using readByte( ), any byte value is a legitimate result so the return value cannot be used to detect the end of input. Instead, you can use the available( ) method to find out how many more characters are available. Here’s an example that shows how to read a file one byte at a time:
t Si on lit les caractères depuis un DataInputStream un byte à chaque fois en utilisant readByte( ), n'importe quelle valeur de byte donne un résultat juste donc la valeur de retour ne peut pas être employée pour détecter la fin de l'entrée. À la place, on peut employer la méthode avalaible( ) pour découvrir combien de caractères sont encore disponibles. Voici un exemple qui montre comment lire un fichier byte par byte :
t t t
//: c11:TestEOF.java // Testing for the end of file // while reading a byte at a time. import java.io.*; public class TestEOF { // Throw exceptions to console: public static void main(String[] args) throws IOException { DataInputStream in = new DataInputStream( new BufferedInputStream( new FileInputStream("TestEof.java"))); while(in.available() != 0) System.out.print((char)in.readByte()); } } ///:~ t
//: c11:TestEOF.java
// Test de fin de fichier
// En lisant un byte a la fois.
import java.io.*;

public class TestEOF {
  // Lance les exeptions vers la console :
  public static void main(String[] args)
  throws IOException {
    DataInputStream in =
      new DataInputStream(
       new BufferedInputStream(
        new FileInputStream("TestEof.java")));
    while(in.available() != 0)
      System.out.print((char)in.readByte());
  }
} ///:~
t t t
Note that available( ) works differently depending on what sort of medium you’re reading from; it’s literally “the number of bytes that can be read without blocking.” With a file this means the whole file, but with a different kind of stream this might not be true, so use it thoughtfully.
t Notons qu'available() fonctionne différemment en fonction du type de ressource depuis laquelle on lit; c'est littéralement « le nombre de bytes qui peuvent être lus sans blocage. » Avec un fichier cela signifie le fichier entier, mais avec une autre sorte d'entrée cela ne pourra pas être possible, alors employez le judicieusement.
t t t
You could also detect the end of input in cases like these by catching an exception. However, the use of exceptions for control flow is considered a misuse of that feature.
t On peut aussi détecter la fin de l'entrée dans des cas comme cela en attrapant une exception. Cependant, l'emploi des exeptions pour le contrôle du flux est considéré comme un mauvais emploi de cette caractéristique.
t t t
t t t
t t
\\\
///
t t t
t
     
Sommaire Le site de Bruce Eckel