Le langage Java dispose d'un certain nombre de flux destinés à différentes utilisations d'entrée/sortie.

Les flux utilisables en mémoire sont ceux s'attachant aux tableaux et aux chaînes de caractères, c'est à dire, CharArrayReader, CharArrayWriter, ByteArrayInputStream, ByteArrayOutputStream pour les premiers et StringReader, StringWriter et StringBufferInputStream.

import java.io.*;
public class Flux {
    public static void main(String args[]) throws IOException {
        String chaine = "Un programme Java Simple";
        StringReader resLecture = new StringReader(chaine);
        int contenu;
        while((contenu = resLecture.read())!= -1) {
          // Affiche chacune des lettres de la chaîne de caractères
          System.out.println((char)contenu); 
        }
    }
}

La création d'un flux entrant connecté à un flux sortant au sein d'un tube (ou canal) est réalisable par l'intermédiaire des classes PipedReader et PipedWriter pour les flux de caractères, ainsi que PipedInputStream et PipedOutputStream pour les flux binaires. Toutes les données entrant dans le flux entrant, ressortent dans le même ordre dans le second associé.

import java.io.*;
public class Flux {
    public static void main(String args[]) throws IOException {
        PipedWriter sortie = new PipedWriter();
        PipedReader entree = new PipedReader(sortie);
        sortie.write('X');
        sortie.write('Y');
        sortie.write('Z');
        System.out.println((char)entree.read()); // Affiche X
        System.out.println((char)entree.read()); // Affiche Y
        System.out.println((char)entree.read()); // Affiche Z
    }
}

Le flux SequenceInputStream permet de concaténer plusieurs flux d'entrée en un seul.

import java.io.*;
import java.util.*;
class Flux {
    public static void main(String args[]) throws IOException {
        Vector vecFlux = new Vector();
        vecFlux.add(new FileInputStream("p1.txt"));
        vecFlux.add(new FileInputStream("p2.txt"));
        vecFlux.add(new FileInputStream("p3.txt"));
        Enumeration listeFlux = vecFlux.elements();
        SequenceInputStream poeme = 
                                                    new SequenceInputStream(listeFlux);
        BufferedReader lecture = new BufferedReader(
                                                    new InputStreamReader(poeme));
        String ligne;
        String contenu = "";
        int i = 1;
        while ((ligne = lecture.readLine()) != null) {
          System.out.println(ligne);
          contenu += i++ + ": " + ligne + "\r\n";
        }
        OutputStreamWriter sortie = new OutputStreamWriter(
                                    new BufferedOutputStream(
                                    new FileOutputStream("poeme.rtf")));
        sortie.write(contenu);
        sortie.flush();
        sortie.close();
        poeme.close();
        lecture.close();
    }
}

Les flux employés dans la sérialisation des objets sont représentés par les classes ObjectInputStream, ObjectOutputStream. Les objets cibles doivent implémenter l'interface java.io.Serializable, ou java.io.Externalizable.

import java.io.*;
import java.util.*;
class Flux {
    public static void main(String args[]) 
                                      throws IOException, ClassNotFoundException {
        String contenu = "Un contenu pour ce fichier !";
        ObjectOutputStream fluxSortieObjet = 
                                                    new ObjectOutputStream(
                                                    new FileOutputStream(
                                                    new File("fichier.txt")));
        fluxSortieObjet.writeObject(contenu);
        System.out.println ("Sauvegarde du fichier objet !");
        fluxSortieObjet.flush();
        fluxSortieObjet.close();
        
        String resultat;
        ObjectInputStream fluxEntreeObjet =new ObjectInputStream(
                                new FileInputStream(
                                new File("fichier.txt")));
        resultat = (String)fluxEntreeObjet.readObject();
        System.out.println ("Lecture du fichier objet !");
        System.out.println(resultat);
        fluxEntreeObjet.close();
    }
}

Pour la lecture de données de type primitif (char, byte, short, int, long, float et double) dans un format indépendant des machines sous-jacentes, sont utilisés les flux spéciaux DataInputStream, DataOutputStream.

import java.io.*;
class Flux {
    public static void main(String args[]) throws IOException {
        ByteArrayOutputStream sortie = new ByteArrayOutputStream();
        DataOutputStream sortieDonnee = 
                                                      new DataOutputStream(sortie);

        sortieDonnee.writeBytes("Une chaîne " 
                                                       + "de caractères quelconque !");
        System.out.println (sortieDonnee.size());
        sortieDonnee.writeInt(2003);
        System.out.println (sortieDonnee.size());
        sortieDonnee.writeDouble(16.32);
        System.out.println (sortieDonnee.size());
        sortieDonnee.flush();
        byte[] tableau = sortie.toByteArray();
        System.out.println(tableau.length);
    }
}

La conservation du nombre de lignes lors d'une opération de lecture est assurée par les flux de dénombrement LineNumberReader et LineNumberInputStream.

import java.io.*;
class Flux {
    public static void main(String args[]) throws IOException {
        System.out.println ("Veuillez saisir une ligne : ");
        InputStreamReader entreeStandard = 
                                        new InputStreamReader(System.in);
        LineNumberReader resLecture = 
                                        new LineNumberReader(entreeStandard);
        String ligne;
        while((ligne = resLecture.readLine()) != null) {
            if(ligne.equals("x")){
                resLecture.close();
                break;
            }
            System.out.println("Contenu de la ligne no" 
                                            + resLecture.getLineNumber() + ":\n" + ligne);
            System.out.println ("Veuillez saisir " 
                                            + "une nouvelle ligne (x pour sortir): ");
        }
    }
}

Les classes PushbackReader et PushbackInputStream sont employées pour une lecture anticipée suivie d'un retour des données lues dans le flux.

import java.io.*;
class Flux {
    public static void main(String args[]) {
        try{
            String repertoire = "c:/java/projets/flux/classes";
            String fichier = "poeme.txt";
            BufferedWriter sortie = new BufferedWriter(
                                    new FileWriter(
                                    new File(repertoire, fichier)));
            String poeme = "Es-tu plus belle es-tu moins belle\n\r"
                        + "qu'auparavant\n\r"
                        + "...\n\r"
                        + "en grave fidélité\n\r"
                        + "affirme chaque jour son évidence blanche";
            sortie.write(poeme);
            sortie.flush();
            sortie.close();

            PushbackReader entree = new PushbackReader(
                                    new BufferedReader(
                                    new FileReader(
                                    new File(repertoire, fichier))));
            int car;
            StringBuffer contenu = new StringBuffer();
            while((car = entree.read()) != -1){
                contenu.append((char)car);
            }
            System.out.println(contenu);
            entree.close();
        }
        catch(FileNotFoundException e){
            System.err.println("Fichier non trouvé !\n" + e);
        }
        catch(IOException e){
            System.err.println("Exception d'entree/sortie !\n" + e);
        }
    }
}
//Autre exemple
public String lireChiffres(PushbackReader pb) {
    char car;
    StringBuffer tampon = new StringBuffer();
    try {
        while (true) {
            car = (char)pb.read();
            if (!Character.isDigit(car))
                break;
            tampon.append(car);
        }
        if (car != -1)
            pb.unread(car);
    }
    catch (IOException e) {
        e.printStackTrace();
    }
    return tampon.toString();
}

Les flux utilisables pour des opérations d'impression de représentations de diverses données selon un format précis, sont PrintWriter et PrintStream.

import java.io.*;
class Flux {
    public static void main(String args[]) throws IOException {
        PrintWriter sortieStandard = new PrintWriter(System.out, true);
        sortieStandard.println("Un contenu quelconque !");
    }

}

La conversion des flux binaires en flux de caractères est réalisée par l'intermédiaire des classes InputStreamReader et OutputStreamWriter.

import java.io.*;
import java.math.BigInteger;
class Flux {
    public static void main(String args[]) {
        try {        
            OutputStreamWriter sortie = 
                            new OutputStreamWriter(
                            new BufferedOutputStream(
                            new FileOutputStream("fibonacci.xml")), "8859_1");

            BigInteger sup  = BigInteger.ONE;
            BigInteger inf = BigInteger.ONE;
            sortie.write("<?xml version=\"1.0\" ");
            sortie.write("encoding=\"ISO-8859-1\"?>\r\n");
            sortie.write("<Fibonacci_Numbers>\r\n");
            for (int i = 1; i <= 20; i++) {
                sortie.write("  <fibonacci index=\"" + i + "\">");
                sortie.write(inf.toString());
                sortie.write("</fibonacci>\r\n");
                BigInteger temp = sup;
                sup = sup.add(inf);
                inf = temp;
            }
            sortie.write("</Fibonacci_Numbers>\r\n");
            System.out.println ("Le fichier 'fibonacci.xml' a ete cree !");
            sortie.flush();
            sortie.close();
        }
        catch (IOException e) {
            System.out.println(e.getMessage());
        }
        catch (Exception e) {
            System.out.println("Une exception a ete levee : " + e);
        }
    }
}

L'écriture et la lecture dans les fichiers nécessitent l'emploi des flux FileReader et FileWriter pour les fichiers textes, ainsi que FileInputStream et FileOutputStream pour les fichiers binaires.

import java.io.*;
import java.util.*;
import java.util.regex .*;
class Flux {
    public static void main(String args[]) throws IOException {
        FileInputStream fluxEntrant = new FileInputStream("poeme.rtf");
        BufferedReader lecture = new BufferedReader(
                                 new InputStreamReader(fluxEntrant));

        String regexp = "^[0-9]*: ";
        Pattern modele = Pattern.compile(regexp);
        Matcher correspondance;
        String ligne, contenu = "";
        while ((ligne = lecture.readLine()) != null) {
            correspondance = modele.matcher(ligne);
            ligne = correspondance.replaceFirst("");
            System.out.println(ligne);
          contenu += ligne + "\r\n";
        }
        FileOutputStream fluxSortant = 
                              new FileOutputStream("poeme_sans_numero.rtf");
        OutputStreamWriter ecriture = new OutputStreamWriter(
                              new BufferedOutputStream(fluxSortant));
        ecriture.write(contenu);
        
        ecriture.flush();
        ecriture.close();
        fluxSortant.close();
        fluxEntrant.close();
        lecture.close();
    }
}

D'autres flux particulièrement utiles dans les opérations d'entrée/sortie permettent de placer en mémoire tampon le contenu des flots fournissant des informations séquentiellement. A cet effet quatre flux sont disponibles, il s'agît de BufferedReader et BufferedWriter pour traiter les caractères, ainsi que BufferedInputStream et BufferedOutputStream pour le traitement des données binaires. Ces flux améliorent sensiblement les performances d'entrée/sorities.

import java.io.*;
import java.util.*;
import java.text.*;
class Flux {
    public static void main(String args[]) {
        try{
            Date datejour = new Date();
            DateFormat dateFormat = DateFormat.getDateInstance(
                                            DateFormat.DEFAULT, Locale.FRENCH);
            String date = dateFormat.format(datejour);
            int nb = 10;
            double res;
            String fichier = "fichier.csv";
            BufferedWriter tampon = new BufferedWriter(
                                                            new FileWriter(fichier));
            PrintWriter sortie = new PrintWriter(tampon);
            for (int i = 1; i <= nb; i++){
                res = 3.14 * i * i / 4;
                sortie.println(date + ";" + i + ";" + res);
            }
            sortie.flush();
            sortie.close();
        }
        catch(IOException e){
           System.out.println (e);
        }
    }
}

Les classes BufferedInputStream et BufferedOutputStream sont dérivées respectivement des classes filtres FilterInputStream et FilterOutputStream. Ces dernières sont chargées de filtrer les flux de données en lecture ou en écriture. Ces deux classes possèdent plusieurs sous-classes souvent utilisées en association avec les flux :

FilterInputStream
  • la classe BufferedInputStream pour lire dans un flux en passant par une mémoire tampon,
  • la classe DataInputStream pour lire dans un flux des données de types primitifs ou des chaînes de caractères,
  • la classe LineNumberInputStream pour compter les lignes d'un flux,
  • la classe PushBackInputStream pour lire dans un flux des octets qui sont ensuite retournés dans ce même flux.
FilterOutputStream
  • la classe BufferedOutputStream pour écrire vers un flux en utilisant une mémoire tampon,
  • la classe DataOutputStream pour écrire vers un flux des données de types primtifs ou des chaînes de caractères,
  • la classe PrintStream pour écrire selon le format appropriés aux types primitifs et aux chaînes de caractèteres.
Télécharger l'ensemble des exemples