next up previous contents index
Next: 15 La hiérarchie des Up: Java: Le langage Previous: 13 Classes imbriquées

Subsections

14 Entrées-Sorties

 

14.1 Introduction

                 

Les entrées/sorties sont basés sur les flots (streams ). Un flot de données est un canal de communication constitué d'une suite ordonnée de données ayant deux extrémités : une entrée et une sortie . Java fournit un moyen de manipuler des flots de données de manière identique quelque soit le système d'exploitation sous-jacent. L'ensemble des classes permettant d'utiliser les entrées/sorties est regroupé dans le package java.io.

Le package java.io contient les classes InputStream et OutputStream. Les classes InputStream et OutputStream sont des classes abstraites qui définissent les méthodes d'entrée/sortie de base. Elles manipulent des suites d'octets.

\begin{rawhtml}

Depuis la version 1.1, les classes Reader et Writer ont été rajoutées au package java.io. La hiérarchie des nouvelles classes suit de près celle des existantes déjà dans la version  1.0 . La principale raison de cette modification est le besoin de gérer les caractères internationaux sur 16 bits aux lieu des 8 bits de l'ancienne version.

Ces classes Reader et Writer sont également des classes abstraites et manipulent comme unité de base le caractère (et non pas l'octet).

Les classes Reader et Writer, tout comme les classes InputStream et OutputStream, sont les classes de base à partir desquelles toutes les autres classes sont dérivées.

On trouve également dans ce package les classes ObjectInputStream et ObjectOutputStream pour lire et écrire des objets.

\begin{rawhtml}

14.2 Hiérarchie des classes et interfaces de java.io

La version 1.1 du package java.io est constitué des packages suivants:


Les Classes:  
BufferedInputStream  
BufferedOutputStream  
BufferedReader  
BufferedWriter  
ByteArrayInputStream  
ByteArrayOutputStream  
CharArrayReader  
CharArrayWriter  
DataInputStream  
DataOutputStream  
File  
FileDescriptor  
FileInputStream  
FileOutputStream  
FileReader  
FileWriter  
FilterInputStream  
FilterOutputStream  
FilterReader  
FilterWriter  
InputStream  
InputStreamReader  
LineNumberInputStream  
LineNumberReader  
ObjectInputStream  
ObjectOutputStream  
ObjectStreamClass  
OutputStream  
OutputStreamWriter  
PipedInputStream  
PipedOutputStream  
PipedReader  
PipedWriter  
PrintStream  
PrintWriter  
PushbackInputStream  
PushbackReader  
RandomAccessFile  
Reader  
SequenceInputStream  
StreamTokenizer  
StringBufferInputStream  
StringReader  
StringWriter  
Writer  


Les interfaces:  
DataInput  
DataOutput  
Externalizable  
FilenameFilter  
ObjectInput  
ObjectInputValidation  
ObjectOutput  
Serializable  


14.2.1 InputStream et OutputStream

Classes de base pour beaucoup d'autres classes, les classes InputStream et OutputStream définissent les méthodes pour lire et écrire dans un flot de données. Ces classes ignorent la structure de données manipulées et se contentent de le ``voir'' comme des suites d'octets. Comme ce sont des classes abstraites, il n'est pas possible de créer des objets de cette classe.

 

Et System.in ???

InputStream et Reader

 
public abstract class InputStream {
    public InputStream()
    public int available() throws IOException
    public void close() throws IOException
    public synchronized void mark(int limite)
    public boolean markSupported(int limite)
    public abstract int read() throws IOException
    public int read(byte[ ] tampon) throws IOException
    public int read(byte[ ] tampon, int debut, int nbre) throws IOException
    public synchronized void reset()throws IOException
    public long skip(long nbre) throws IOException

}

 public abstract int read () throws IOException

Cette méthode lit un octet sur le flot spécifié et retourne cette valeur sous la forme d'un entier. Il s'agit d'une lecture bloquante. Si la valeur retournée est -1, cela indique que l'on atteint la fin normale du flot. On peut ainsi tester cette valeur pour gérer l'erreur ``fin de flot de données''. Cela étant, en cas d'une quelconque erreur lors de la lecture, une exception IOException est levée. Il convient alors de capturée cette exception et gérer toutes les erreurs possibles. Une utilisation standard de cette méthode ressemble à ce qui suit :
 
try {
    int intLu = System.in.read();
    ...
}
catch (IOException e) {
    ...
}
La valeur retournée est un int et non pas un byte. Un octet lu (et non pas le code d'erreur) est un entier compris entre 0 et 255. Pour pouvoir l'utiliser comme un byte, il faut le transformer en byte :
 
byte  byteLu = (byte) intLu;
 public int read (byte[ ] tampon) throws IOException
Cette méthode lit dans le flot d'entrée une suite d'octets et les range dans le tableau tampon. Le nombre d'octets lus correspond à la taille du tableau (qui est donnée par tampon.length). Cette méthode retourne -1 en cas de fin de flot et le nombre d'octets lus autrement. Ces deux méthodes sont également bloquantes jusqu'à ce que l'entrée soit disponible.
 
byte [ ] tampon = new byte[ 200 ];
int nb_car_lus = System.in.read(tampon);
 public int read (byte[ ] tampon, int debut, int nbre) throws IOException
Cette méthode lit dans le flot d'entrée une suite d'octets et les range dans le tableau tampon à partir de l'indice debut. Le nombre d'octets à lire est donné par la variable nbre. Cette méthode retourne -1 en cas de fin de flot et le nombre d'octets lus autrement.
 
byte [ ] tampon = new byte[ 200 ];
int nb_car_lus = System.in.read(tampon, 10, 20);
 public int available () throws IOException
La méthode available permet de déterminer le nombre d'octets disponible sur l'entrée. Ceci permet, par exemple, d'allouer dynamiquement le tableau dans lequel on va ranger les octets lus.
 
int disponible = System.in.available();
if (disponible > 0) {
    byte [ ] tampon = new byte[ disponible ];
    nb_car_lus = System.in.read(tampon);
    ...
}
Cette méthode ne s'applique pas à l'entrée standard. Le nombre d'octets disponible n'a de sens que sur les fichiers. Pour l'entrée standard, on aura toujours pour valeur 0.
 public long skip (long nbre) throws IOException
La méthode skip permet de sauter le nombre nbre d'octets dans le flot d'entrée. Cette méthode n'est là que pour des problèmes de performances. Si la fin du flot survient avant les nbre octets, le flot est positionné à sa fin.
 public void close () throws IOException
Cette méthode referme le flot d'entrée et libère les ressources systèmes.
 public void mark (int readlimit)
Marque la position courante du flot d'entrée ce qui permet de repositionner le flot à cette marque lors de l'invocation de la méthode reset. L'argument readlimit donne le nombre d'octets pouvant être lus avant la marque devienne invalide.
 public void reset () throws IOException
Repositionne le flot à la marque repérée par la méthode mark. L'exception IOException est levée si la marque est invalidée ou inexistante.
 public boolean markSupported ()
Retourne vrai si le flot implante les méthode mark et reset.

La classe Reader est similaire joue le même rôle que la classe InputStream mais elle agit sur les caractères.

 
public abstract class Reader {
    protected Reader(Object lock)
    protected Reader()
    public int available() throws IOException
    public void close() throws IOException
    public synchronized void mark(int limite)
    public boolean markSupported(int limite)
    public abstract int read() throws IOException
    public int read(char[ ] tampon) throws IOException
    public int read(char[ ] tampon, int debut, int nbre) throws IOException
    public boolean ready() throws IOException
    public synchronized void reset()throws IOException
    public long skip(long nbre) throws IOException
}

OutputStream et Writer

Toutes les méthodes, excepté le constructeur, lève une exception en cas d'erreur.

 

   public class OutputStream {
      public OutputStream()
      public abstract void write(int b) throws IOException
      public void write(byte b[]) throws IOException
      public void write(byte b[], int off, int len) throws IOException
      public void flush() throws IOException
      public void close() throws IOException
   }

 public abstract void write (int b) throws IOException

Cette méthode écrit un octet sur le flot de sortie. L'octet à écrire est passé en argument sous la forme d'une int et non pas sous la forme d'un byte. Rappelons que les expressions qui manipulent les bytes sont de type int; il en découle qu'il n'est pas nécessaire faire une conversion explicite lors du passage de ce paramètre. Les bits de poids forts de cet int sont évidemment perdus lors de l'écriture. Cette méthode est bloquante jusqu'à la réalisation de l'écriture.
 public void write (byte b[ ] tampon) throws IOException
Cette méthode écrit un tableau d'octets sur le flot de sortie.
 public void write (byte b[ ] tampon, int debut, int nbre) throws IOException
Cette méthode écrit les octets du tableau tampon à partir de l'indice debut. Le nombre d'octets à écrire est donné par le paramètre nbre.
 public void flush () throws IOException
Vide le tampon de sortie dans le flot de sortie.
 public void close () throws IOException
Cette méthode referme le flot de sortie et libère les ressources système relatives à ce flot.

La classe Writer est similaire joue le même rôle que la classe OutputStream mais elle agit sur les caractères.

 
class abstract  Writer  
  protected Writer()
  protected Writer(Object lock)
  public void write(int c) throws IOException
  public void write(char cbuf[]) throws IOException
  public abstract void write(char cbuf[], int off, int len) throws IOException
  public void write(String str) throws IOException
  public void write(String str, int off, int len) throws IOException
  public abstract void flush() throws IOException
  public abstract void close() throws IOException

14.2.2 Les classes dérivées de bas niveau

Les classes dérivées de InputStream, Reader, OutputStream et Writer sont construites selon l'origine ou la destination du flot utilisé:

De plus, les classes FilterInputStream et FilterOutputStream est définie pour servir de classe de base pour manipuler, non pas des octets ou des caractères, des objets de plus haut niveau.

Les classes dérivées de Reader (resp. Writer) et celles dérivées de InputStream (resp. OutputStream) ne se distinguent que par le fait que les premiers manipulent des caractères et les seconds, des octets:

14.2.3 Les entrées sorties structurées

Contrairement aux classes que nous venons d'évoquer, celles qui suivent permettent de manipuler des données structurées.

14.2.4 Autres classes

14.2.5 Les interfaces

14.3 Les entrées/sorties standard (terminal)

L'interface avec le système d'exploitation est gérée par la classe java.lang.System. La gestion des entrées/sorties standard passe par les objets System.in (entrée standard , équivalent de stdin), System.out (sortie standard , équivalent de stdout) et System.err (sortie erreur , équivalent de stderr).

 
public final class System extends Object {
        ...
        public static PrintStream err, out;
        public static InputStream in;
        ...
}
Les sorties ne sont pas des références vers des objets de la classe OutputStream mais plutôt de la classe PrintStream qui donne une représentation textuelle des données. Nous verrons plus loin et en détails la classe PrintStream. Pour le moment, contentons nous de remarquer que c'est une sous classe de la classe OutputStream.

De même, l'entrée est déclaré comme un objet de la classe InputStream. Cette classe est une classe abstraite et l'objet in est en réalité une instance de la classe BufferedInputStream.

 

   class Cat {
      public static void main(String[] args)  throws java.io.IOException {
         int c, count=0;
         while ((c = System.in.read()) != -1) {
            count++;
            System.out.write(c);
         }
         System.out.println("Input has " + count + " chars.");
      }
   }

Noter que le retour de la méthode read est un int; ce qui permet de tester une fin de fichier avec la valeur -1.

14.4 Les entrées/sorties de type filter

14.4.1 FilterInputStream, FilterOutputStream, FilterReader et FilterWriter

Les flots de type filter sont conçus pour une faciliter la manipulation des données d'un flot en appliquant un certain type de filtrage. Par exemple, les classes FilterInputStream et FilterReader proposent des méthodes qui filtrent les octets ou caractères reçus, à travers un filtre défini dans l'interface InputFilter, et revoient une valeur sous la forme d'un objet un peu plus plus structuré qu'un octet.

Les constructeurs de ses classes prennent, selon le cas, en argument un flot de type InputStream ou Reader.

En fait, cette classe redéfinit toutes les méthodes de la classe InputStream et Reader.

De même, les classes FilterOutputStream et FilterWriter proposent des méthodes qui structurent les données à rendre.

Les classes FilterInputStream, FilterReader, FilterOutputStream et FilterWriter ne sont pas intéressantes pour elles-mêmes : elles servent de classe de base pour des classes plus utilisées.

De la classe FilterInputStream, on dérive les classes

De la classe FilterOutputStream, on dérive les classes

De la classe FilterReader, on dérive les classes

14.4.2 Définir ses propres filtres

14.5 Les fichiers

Avec la classe File, Java permet de manipuler les fichiers selon la même convention quelque soit la système d'exploitation. Elle permet également des méthodes pour manipuler les répertoires, ``lister'' les fichiers d'un répertoire, examiner les propriétés d'un fichier, etc.

14.5.1 La classe FileDescriptor

 

A TERMINER

14.5.2 La classe File

 

   public class File extends Object {
      public final static String pathSeparator;
      public final static String pathSeparatorChar;
      public final static String separator;
      public final static String separatorChar;
      public File(String chemin) throws NullPointerException;
      public File(String chemin, String nom);
      public File(String repertoire, String nom);

      public boolean canRead();
      public boolean canWrite();
      public boolean delete();
      public boolean equals(Object obj);
      public boolean exists();
      public String getAbsolutePath();
      public String getName();
      public String getParent();
      public String getPath();
      public String getPath();
      public int hashCode();
      public boolean isAbsolute();
      public boolean isDirectory();
      public boolean isFile();
      public long lastModified();
      public long length();
      public String [ ] list();
      public String [ ] list(FilenameFilter filtre);
      public boolean mkdir();
      public boolean mkdirs();
      public boolean renameTo();
      public String toString();
   }

Les objets de type File désignent des répertoires ou des fichiers. Pour créer un tel objet, on utilise évidemment un des constructeurs de cette classe qui prend en argument selon le cas :

 
File fichier1   = new File("/tmp/toto.txt");      // fichier avec nom absolu
File répertoire = new File("/tmp");               // répertoire avec nom absolu
File fichier2   = new File("toto.txt");           // nom relatif
File fichier3   = new File("/tmp","toto.txt");
File fichier4   = new File(répertoire,"toto.txt");
La création d'un objet de type File n'engendre pas d'erreurs; il n'est pas nécessaire que le fichier ou répertoire spécifié existe. Comme on peut le remarquer, les méthodes de cette classe ne permettent pas d'écrire ou de lire dans le fichier spécifié. Pour pouvoir le faire, on passera par la création d'un objet de la classe FileInputStream ou FileOutputStream.

La classe File dispose de méthodes pour

14.5.3 Les classes FileInputStream, FileReader, FileOutputStream et FileWriter

La classe FileInputStream permet lire des données à partir d'un fichier désigné par un objet de type File ou FileDescriptor.

 

   public class FileInputStream extends InputStream {
      public FileInputStream(String nom) throws FileNotFoundException, IOException;
      public FileInputStream(File f) throws FileNotFoundException, IOException;
      public FileInputStream(FileDescriptor f);
      public int available() throws IOException;
      public void close() throws IOException;
      public final FileDescriptor getFD() throws IOException;
      public int read() throws IOException;
      public int read(byte[ ] tampon) throws IOException;
      public int read(byte[ ] tampon, int debut, int nbre) throws IOException;
      public long skip(long nbre) throws IOException;
      protected void finalize()throws IOException;
   }

De même, la classe FileReader permet lire des fichiers de caractères; fichiers désignés par un objet de type File ou FileDescriptor.

 

public class FileReader  extends InputStreamRaeder {
  FileReader(String fileName)
  FileReader(File file)
  FileReader(FileDescriptor fd)
}

La classe FileWriter permet d'écrire dans des fichiers, des caractères. Ces fichiers désignés par un objet de type File ou FileDescriptor.

 

   public class FileWriter extends OutputStreamWriter {
      public FileWriter(String fileName)
      public FileWriter(String fileName, boolean append)
      public FileWriter(File file)
      public FileWriter(FileDescriptor fd)
   }

Voici une exemple de programme qui recopie un fichier dans un répertoire ou sous un autre nom.

 

   import java.io.*;

   public class CopieFichier {
      public static void main(String[] args) throws IOException {
         if (args.length != 2)
            System.err.println("Usage: java CopieFichier FichierSource FichierDestination");
         else {
            File src = new File(args[0]), dest = new File(args[1]);
            FileInputStream fsrc = null;
            FileOutputStream fdest = null;
            if (!src.exists()) erreur(args[0] + "Introuvable");
            if (!src.isFile()) erreur(args[0] + " n'est pas un fichier");
            if (!src.canRead()) erreur(args[0] + " Interdit de lecture");
            if (dest.isDirectory()) dest = new File(dest, src.getName());
            if (dest.exists()) {
               if (!dest.canWrite()) erreur(args[1]+ " Interdit d'écriture");
               System.out.print("Remplacer le fichier " + args[1] + " existant? (O/N): ");
               System.out.flush();
               BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
               String response = in.readLine();
               if (!response.equals("O") && !response.equals("o")) erreur("Copie annulée");
            }
            else {
               String parent = dest.getParent();
               if (parent == null) parent = System.getProperty("user.dir");
               File dir = new File(parent);
               if (!dir.exists()) erreur("FileCopy: destination directory doesn't exist: " + parent);
               if (dir.isFile()) erreur("FileCopy: destination is not a directory: " + parent);
               if (!dir.canWrite()) erreur("FileCopy: destination directory is unwriteable: " + parent);
            }
            fsrc = new FileInputStream(src);
            fdest = new FileOutputStream(dest);
            byte[] buffer = new byte[4096];
            int bytes_read;
            while((bytes_read = fsrc.read(buffer)) != -1)
               fdest.write(buffer, 0, bytes_read);
         
            if (fsrc != null)  fsrc.close(); 
            if (fdest != null)  fdest.close(); 
         }
      }
      private static void erreur(String msg) throws IOException {
         throw new IOException(msg);
      }
   }

14.5.4 L'interface FilenameFilter

Cette interface permet, comme son nom l'indique, de choisir un sous ensemble des fichiers disponibles en les filtrant selon un critère qu'implante la méthode accept; méthode unique de cette interface.

 
public interface FilenameFilter {
    public boolean accept(File dir, String name)
}

Voici une exemple de programme qui affiche les fichiers sources Java du répertoire courant.

 

   import java.io.*;

   public class FiltreFichierJava implements FilenameFilter {
      public static void main(String args[]) throws IOException {
         File f = new File(".");
         FilenameFilter filter = new FiltreFichierJava();
         System.out.println("Fichiers Java : " );
         String[] noms = f.list(filter);
         for (int i = 0;  noms != null && i < noms.length; i++)
            System.out.println("\t" + noms[i]);
      }
   
      public boolean accept(File dir, String name) {
         return (name.endsWith(".java"));
      }
   }


14.5.5 FilePermission

 

A TERMINER

14.6 DataInputStream et DataOutputStream

Les classes DataOutputStream et DataInputStream sont des flots de type filtre spécialisés pour la reconnaissance des types primitifs de Java ainsi que des chaînes de caractères. C'est généralement ces classes qui sont les plus utilisées dans les applications standards. Cette classe décharge donc le programmeur de la nécessité de réorganiser les données reçues (entrée) ou envoyer (sortie) en données primitives.

 

   public class DataInputStream extends FilterInputStream implements DataInput {
      public DataInputStream(InputStream in)
      public final int read(byte b[]) throws IOException
      public final int read(byte b[],                        int off,
                        int len) throws IOException
      public final void readFully(byte b[]) throws IOException
      public final void readFully(byte b[],                              int off,
                              int len) throws IOException
      public final int skipBytes(int n) throws IOException
      public final boolean readBoolean() throws IOException
      public final byte readByte() throws IOException
      public final int readUnsignedByte() throws IOException
      public final short readShort() throws IOException
      public final int readUnsignedShort() throws IOException
      public final char readChar() throws IOException
      public final int readInt() throws IOException
      public final long readLong() throws IOException
      public final float readFloat() throws IOException
      public final double readDouble() throws IOException
      public final String readLine() throws IOException
      public final String readUTF() throws IOException
      public final static String readUTF(DataInput in) throws IOException
   }

Le constructeur de la classe DataInputStream prend en argument un objet de type InputStream. Pour chaque type primitive, on dispose d'une méthode : readBoolean, readByte, readChar, readDouble, readFloat, readInt, readLong, readShort. De même les chaînes de caractères peuvent être lues par la méthode readLine. Le format UTF (Unicode Transformation Format ) est une format de conversion d'une chaîne de caractères Unicode en une chaîne de caractères ASCII .

Un objet DataInputStream peut être utilisé pour les flots de type fichier , socket ou entrée standard .

 
DataInputStream entrée = new DataInputStream(System.in);
int entier = entrée.readInt();
String chaîne = entrée.readString();
...

La classe DataOutputStream écrit sur le flot de sortie spécifié des données primitives et des chaînes de caractères.

 

   public class DataOutputStream extends FilterOutputStream implements DataOutput {
      protected int written
      public DataOutputStream(OutputStream out)
      public void flush() throws IOException
      public int size() throws IOException
      public synchronized void write(int b) throws IOException
      public synchronized void write(byte b[ ], int debut, int nbre) throws IOException
      public final void writeBoolean(boolean v) throws IOException
      public final void writeByte(int v) throws IOException
      public final void writeBytes(String s) throws IOException
      public final void writeChar(int v) throws IOException
      public final void writeChars(String s) throws IOException
      public final void writeDouble(double v) throws IOException
      public final void writeFloat(float v) throws IOException
      public final void writeInt(int v) throws IOException
      public final void writeLong(long v) throws IOException
      public final void writeShort(int v) throws IOException
      public final void writeUTF(String s) throws IOException
   }

Le constructeur de la classe DataOutputStream prend en argument un objet de type OutputStream. Pour chaque type primitive, on dispose d'une méthode : writeBoolean, writeByte, writeChar, writeDouble, writeFloat, writeInt, writeLong, writeShort. De même les chaînes de caractères peuvent être écrites par la méthode writeChars ou writeBytes.

Un objet DataOutputStream peut être utilisé pour les flots de type fichier , socket ou sortie standard et sortie erreur .

 
DataOutputStream sortie = new DataOutputStream(System.out);
sortie.writeInt(254);
sortie.writeString("Coucou");
...

14.7 PrintStream et PrintWriter

Autre extension de la classe FilterOutputStream, la classe PrintStream est utilisée chaque fois que l'on désire obtenir un représentation textuelle des données de type primitif ou des chaînes de caractères. Les méthodes utilisées sont println et print selon que l'on veuille passer ou pas à la ligne suivante après l'écriture des données.

La classe PrintStream ne sait pas gérer les caractères Unicode . Sur les 16 bits utilisés pour coder un caractère Unicode , les 8 bits de poids forts seront perdus lors de l'écriture.

La représentation textuelle d'un objet quelconque est réalisée s'il existe une méthode toString dans la définition de sa classe. Cette méthode fait partie des méthode de la classe Object.

 

public class PrintStream extends FilterOutputStream {
    public PrintfStream(OutputStream out)
    public PrintfStream(OutputStream out, boolean autoflush)
    public boolean checkError()
    public void close()
    public void print(Object obj)
    public synchronized void print(String s)
    public synchronized void print(char [ ] s)
    public void print(char c)
    public void print(int i)
    public void print(long  l)
    public void print(float f)
    public void print(double d)
    public void print(boolean b)
    public void println()
    public synchronized void println(Object obj)
    public synchronized void println(String s)
    public synchronized void println(char [ ] s)
    public synchronized void println(char c)
    public synchronized void println(int i)
    public synchronized void println(long  l)
    public synchronized void println(float f)
    public synchronized void println(double d)
    public synchronized void println(boolean b)
    public void write(int b) throws IOException
    public void write(byte[ ]  b, int début, int nbre) throws IOException
}

Pour pouvoir écrire l'ensemble des caractères Unicode , on utilisera la classe PrintWriter. Depuis la version 1.1, on utilisera plutôt la classe PrintWriter

 

public class PrintWriter extends Writer {
  PrintWriter(Writer out)
  PrintWriter(Writer out, boolean autoFlush)
  PrintWriter(OutputStream out)
  PrintWriter(OutputStream out, boolean autoFlush)
  boolean checkError()
  void close()
  void flush()
  void print(boolean b)
  void print(char c)
  void print(int i)
  void print(long l)
  void print(float f)
  void print(double d)
  void print(char[] s)
  void print(String s)
  void print(Object obj)
  void println()
  void println(boolean x)
  void println(char x)
  void println(int x)
  void println(long x)
  void println(float x)
  void println(double x)
  void println(char[] x)
  void println(String x)
  void println(Object x)
  void setError()
  void write(int c)
  void write(char[] buf, int off, int len)
  void write(char[] buf)
  void write(String s, int off, int len)
  void write(String s)
}

On notera que cette classe n'est pas une classe dérivée de la classe FilterWriter mais est une classe directement dérivée de la classe Writer.

Nous avons déjà utilisé ce type d'objet; la variable static System.out est une instance de la classe PrintWriter.

14.8 BufferedInputStream, BufferedReader, BufferedOutputStream et BufferedWriter

Chacune de ces classes disposent de deux constructeurs:

 
BufferedInputStream(InputStream in)
BufferedOutputStream(InputStream in, int size)

BufferedReader(Reader in)
BufferedReader(Reader in, int size)

BufferedOutputStream(OutputStream out)
BufferedOutputStream(OutputStream out, int size)

BufferedWriter(Writer out)
BufferedWriter(Writer out, int size)

L'argument size définit la taille de la zone d'entrée sortie tampon que l'on veut associer au flot. Lorsque cet argument n'est pas donné, une taille par défaut est fixée (512 octets).

Ces classes redéfinissent certaines des méthodes de leur classe père et n'introduisent aucune méthode supplémentaire.

 

A TERMINER
Exemple

14.9 LineNumberInputStream et LineNumberReader

Depuis la version 1.1, la classe LineNumberReader remplace la classe LineNumberInputStream.

Les classes LineNumberInputStream et LineNumberReader conserve l'information sur les numéros de lignes du flot. Une ligne est une suite de caractères se terminant par '
r'
(carriage return ) ou par '
n'
(line feed ).

Il existe un unique constructeur pour la classe LineNumberInputStream

 
LineNumberInputStream(InputStream in)

et deux constructeurs pour la classe LineNumberReader

 
LineNumberReader(Reader in)
LineNumberReader(Reader in, int sz)

Ces deux classes contiennent les méthodes qui permettent la gestion des lignes.

 
int getLineNumber()
void setLineNumber(int lineNumber)

Les méthode mark et reset gèrent également les numéros de lignes, comme on peut s'y attendre.

 

A TERMINER
Exemple

14.10 ByteArrayInputStream, ByteArrayOutputStream, CharArrayReader et CharArrayWriter

Ces classes permettent d'utiliser un tableau pour flot de données.

La classe ByteArrayInputStream possède deux constructeurs:

 
ByteArrayInputStream(byte[] buf)
ByteArrayInputStream(byte[] buf, int offset, int length)
L'argument buf est le flot d'entrée dans les deux cas; dans le deuxième cas, seul la partie du tableau comprise entre les indices offset et offset+length-1 constitue le flot d'entrée.

Toutes les autres méthodes ( available, close, mark, markSupported, read, reset, skip) sont héritées de la classe InputStream.

La classe ByteArrayOutputStream possède deux constructeurs:

 
public ByteArrayOutputStream()
public ByteArrayOutputStream(int size)
Le premier constructeur crée un tableau d'octets dont la taille initiale est de 32 octets; si un tableau plus grand est nécessaire, Java redimenssionne automatiquement celui-ci. Le deuxième constructeur fixe la taille initiale du tableau.

 public void writeTo (OutputStream out) throws IOException

Ecrit le contenu du tableau dans l'argument out. Equivalent à write(buf, 0, count).
 public void reset ()
Remet à zéro la valeur du champ count de manière de supprimer tout ce qui a été rangé dans le tableau.
 public byte[] toByteArray ()
Crée une copie du tableau et retourne ce nouveau tableau.
 public String toString (String enc) throws UnsupportedEncodingException
Converti le tableau en un String et retourne ce dernier.

 

A TERMINER
encoding

Toutes les autres méthodes ( close, write) sont héritées de la classe OutputStream.

 

   import java.io.*;

   public class ByteArray {
      public static void main(String[] args) {
         byte[] tabEntrée = { (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e'};
         ByteArrayInputStream entrée = new ByteArrayInputStream(tabEntrée);
         ByteArrayOutputStream sortie = new ByteArrayOutputStream();
         int b;
         while ((b=entrée.read()) >= 0) sortie.write(b);
         entrée.reset();
         entrée.skip(3);
         while ((b=entrée.read()) >= 0) sortie.write(b);
         System.out.println(sortie);
      }
   }

14.11 StringBufferInputStream, StringReader et StringWriter

Ces classes permettent d'utiliser un objet de type String pour flot de données. La classe StringBufferInputStream est remplacé par la classe StringReader.

 

   public class StringReader extends Reader {
      StringReader(String s) {}
      void close() {}
      void mark(int readAheadLimit)  {}
      boolean markSupported() {}
      int read() {}
      int read(char[] cbuf, int off, int len) {}
      boolean ready() {}
      void reset() {}
      long skip(long ns) {}
   }

 

   public class StringWriter extends Writer {
      StringWriter()
      StringWriter(int initialSize)
      void  close()
      void flush()
      StringBuffer getBuffer()
      String toString()
      void write(int c)
      void write(char[] cbuf, int off, int len)
      void write(String str)
      void write(String str, int off, int len)
   }

14.12 InputStreamReader et OutputStreamWriter

Les classes InputStreamReader et InputStreamReader permettent la conversion des flots d'octets en flots de caractères et inversement.

Supponsons que l'on veuille transformer l'entrée standard (qui est un InputStream) en un BufferedReader. Les constructeurs de la classe BufferedReader prennent un objet de type Reader en argument et non pas un InsputStream. Il faut donc convertir System.in en un Reader:

 
Reader in = new InputStreamRaeder(System.in);
On peut alors obtenir un BufferedReader à partir de ce nouvel objet:
 
BufferedReader bin = new BufferedReader(in);

14.13 PushBackInputStream et PushBackReader

Avec cette classe, il est possible d'effectuer une lecture de données permettant de ``revenir'' sur la dernière lecture. Les analyseurs lexicaux ont souvent besoin de cette possibilité.

 

   public class PushbackInputStream extends FilterInputStream {
      byte[]   buf
      int   pos
      PushbackInputStream(InputStream in, int size)
      PushbackInputStream(InputStream in)
      int   available()
      void   close()
      boolean   markSupported()
      int   read()
      int   read(byte[] b, int off, int len)
      long   skip(long n)
      void   unread(int b)
      void   unread(byte[] b, int off, int len)
      void   unread(byte[] b)
   }

 

A TERMINER
Exemple

14.14 PipedInputStream, PipedReader, PipedOutputStream et PipedWriter

Les classes PipedInputStream, PipedReader, PipedOutputStream et PipedWriter implante les entrées sorties pour les tubes (pipes ).

14.14.1 PipedInputStream, PipedReader

 

   public class PipedInputStream extends InputStream {
      byte[]   buffer;
      int in;
      int out;
      static int PIPE_SIZE;
      PipedInputStream(PipedOutputStream src)
      PipedInputStream()
      int available()
      void close()
      void connect(PipedOutputStream src)
      int read()
      int read(byte[] b, int off, int len)
      void receive(int b)
   }

 

   public class PipedReader extends Reader {
      PipedReader()
      PipedReader(PipedWriter src)
      void   close()
      void   connect(PipedWriter src)
      int   read(char[] cbuf, int off, int len)
   }

14.14.2 PipedOutputStream, PipedWriter

 

   public class PipedOutputStream extends OutputStream {
      PipedOutputStream(PipedInputStream snk)
      PipedOutputStream()
      void close()
      void connect(PipedInputStream snk)
      void flush()
      void write(int b)
      void write(byte[] b, int off, int len)
   }

 

   public class PipedWriter extends Writer {
      PipedWriter()  {}
      PipedWriter(PipedReader sink)  {}
      void   close()   {}
      void   connect(PipedReader sink)  {}
      void   flush()   {}
      void   write(char[] cbuf, int off, int len)  {}
   }

Le squelette d'un programme type utlisant les tubes pour connecter les sorties d'un premier thread à l'entrée d'un deuxième thread est de la forme suivante:

 
    ...
    public static void main(String[] args) throws IOException {
        PipedOutputStream prod = new PipedOutputStream();
        PipedInputStream cons = new PipedInputStream();

        consumer.connect(producer);

        PremierThread th1  = new PremierThread (cons);
        DeuxiemeThread th2 = new DeuxiemeThread(prod);

        th1.start();
        th2.start();

        try {  Thread.sleep(5000); }
        catch (InterruptedException e) {}

        th1.stop();
        th2.stop();

        prod.close();
        cons.close();
    }
    ...

Exemple

 

A TERMINER

14.15 SequenceInputStream

 

A TERMINER

14.16 RandomAccessFile

Les fichiers dont nous avons parlé jusqu'à présent étaient des fichiers séquentiels. Java fournit une gestion pour les fichiers à accès non séquentiel. Par exemple, ce type de fichier est intéressant pour les fihiers zip; l'extraction d'un fichier contenu dans un fichier zip sera bien plus efficace avec un RandomAccessFile qu'un fichier séquentiel standard.

 

\begin{formatprog}\begin{verbatim}
public class RandomAccessFile extends Object implements DataOutput, DataInput {
      public RandomAccessFile(String name, String mode) throws IOException
      public RandomAccessFile(File file, String mode) throws IOException
      public final FileDescriptor getFD() throws IOException
      public int read() throws IOException
      public int read(byte b[], int off, int len) throws IOException
      public int read(byte b[]) throws IOException
      public final void readFully(byte b[]) throws IOException
      public final void readFully(byte b[], int off, int len) throws IOException
      public int skipBytes(int n) throws IOException
      public void write(int b) throws IOException
      public void write(byte b[]) throws IOException
      public void write(byte b[], int off, int len) throws IOException
      public long getFilePointer() throws IOException
      public void seek(long pos) throws IOException
      public long length() throws IOException
      public void close() throws IOException
      public final boolean readBoolean() throws IOException
      public final byte readByte() throws IOException
      public final int readUnsignedByte() throws IOException
      public final short readShort() throws IOException
      public final int readUnsignedShort() throws IOException
      public final char readChar() throws IOException
      public final int readInt() throws IOException
      public final long readLong() throws IOException
      public final float readFloat() throws IOException
      public final double readDouble() throws IOException
      public final String readLine() throws IOException
      public final String readUTF() throws IOException
      public final void writeBoolean(boolean v) throws IOException
      public final void writeByte(int v) throws IOException
      public final void writeShort(int v) throws IOException
      public final void writeChar(int v) throws IOException
      public final void writeInt(int v) throws IOException
      public final void writeLong(long v) throws IOException
      public final void writeFloat(float v) throws IOException
      public final void writeDouble(double v) throws IOException
      public final void writeBytes(String s) throws IOException
      public final void writeChars(String s) throws IOException
      public final void writeUTF(String str) throws IOException
   }
\end{verbatim}\end{formatprog}

 

A TERMINER

14.17 StreamTokenizer

Java fournit, avec la classe StreamTokenizer, des facilités pour faire des analyses relativement simples. Le processus d'analyse est contrôlé par une table d'analyse et un certain nombre de drapeaux (flags ). Les données en entrée sont découpées en unités lexicales et chaque unité lexicale est lue d'un coup. La lecture d'une unité lexicale se fait grâce à la méthode nextToken.

 

   public class StreamTokenizer {
      public int ttype
      public final static int TT_EOF
      public final static int TT_EOL
      public final static int TT_NUMBER
      public final static int TT_WORD
      public String sval
      public double nval
      public StreamTokenizer(InputStream is)
      public StreamTokenizer(Reader r)
      public void resetSyntax()
      public void wordChars(int low, int hi)
      public void whitespaceChars(int low, int hi)
      public void ordinaryChars(int low, int hi)
      public void ordinaryChar(int ch)
      public void commentChar(int ch)
      public void quoteChar(int ch)
      public void parseNumbers()
      public void eolIsSignificant(boolean flag)
      public void slashStarComments(boolean flag)
      public void slashSlashComments(boolean flag)
      public void lowerCaseMode(boolean fl)
      public int nextToken() throws IOException
      public void pushBack()
      public int lineno()
      public String toString()
   }

 public int nextToken () throws IOException

Lit l'unité lexicale suivante et retourne le type de l'unité lexicale reconnue; type stocké également dans le champ ttype de cette classe. Les champs nval et sval contiennent des informations complémentaires sur l'unité lexicale lue.

Les champs

Les constantes

Le flot d'entrée est composé de caractères "spéciaux" (qui vont avoir un sens particulier) et des caractères ordinaires:

Les programmes qui utilisent la classe StreamTokenizer ressemble très souvent à :

 

   import java.io.*;

   public class Analyse {
      public static void main(String args[]) throws Exception {
         if (args.length != 1) {
            System.out.println("usage: java Analyse <fichier>");
            System.exit(0);
         }
         StreamTokenizer in = new StreamTokenizer(new FileReader(args[0]));
         while (in.nextToken() != StreamTokenizer.TT_EOF) {
            
            switch (in.ttype) {
               case StreamTokenizer.TT_EOL :
                  System.out.println("Fin de ligne");
                  break;
               case StreamTokenizer.TT_NUMBER :
                  System.out.println("Nombre      " + in.nval);
                  break;
               case StreamTokenizer.TT_WORD :
                  System.out.println("Mot         " + in.sval);
                  break;
               case '\'' :
               case '"' :
                  System.out.println("Chaine      " +  in.sval);
                  break;
            default: 
                  System.out.println("Caractère   " + (char)in.ttype);
            }
         }
      }
   }

Il existe des méthodes pour redéfinir les caractères spéciaux, ordinaires, etc:

 public void wordChars (int low, int hi)

Les caractères compris dans l'intervalle [low, hi] deviennent des caractères qui composent un mot.
 public void whitespaceChars (int low, int hi)
Les caractères compris dans l'intervalle [low, hi] deviennent des séparateurs.
 public void ordinaryChars (int low, int hi)
Les caractères compris dans l'intervalle [low, hi] deviennent des caractères oridinaires.
 public void ordinaryChar (int ch)
Le caractère ch devient un caractère oridinaire.
 public void commentChar (int ch)
Le caractère ch marque le début d'un commentaire.
 public void quoteChar (int ch)
Les chaînes de caractères peuvent être délimités par le caractère ch.
 public void eolIsSignificant (boolean flag))
Si flag est faux, une fin de ligne est traité comme le caractère espace i.e. comme un séparateur; faux est la valeur par défaut.
 public void slashStarComments (boolean flag))
Si flag est vrai, un texte encadré par /* et */ est considéré comme un commentaire; faux est la valeur par défaut.
 public void slashSlashComments (boolean flag))
Si flag est vrai, un texte encadré commençant // est considéré comme un commentaire ligne; faux est la valeur par défaut.
 public void lowerCaseMode (boolean flag))
Si flag est vrai, tous les caractères des unités lexicales sont convertis en minuscules; faux est la valeur par défaut.
 public void pushBack ())
Remet dans le flot la dernière unité lexicale lue. Une seule unité lexicale peut être remis; il est équivalent de faire plusieurs appels ou un seul appel de cette méthode.
 public int lineno ())
Retourne le numéro de ligne courante; utile pour préciser les erreurs.
 public void resetSyntax ()
Supprime toutes les définitions de syntaxe. Tous les caractères deviennent des caractères oridinaires; une unité lexicale devient tout simplement le prochain caractère.
 public void parseNumbers ()
 

A TERMINER


next up previous contents index
Next: 15 La hiérarchie des Up: Java: Le langage Previous: 13 Classes imbriquées
Touraivane
6/12/1998