Les flux
Objectifs du chapitre
Ce chapitre a pour objectif de comprendre la hiérarchie et le fonctionnement des classes de gestion des flux de Java. De plus, il vous permettra de développer des applications utilisant des fichiers (texte ou binaires).
Définition
Les flux permettent d’effectuer les opérations de lecture et d’écriture de données.
La source et la destination des données sont diverses : clavier, écran, réseau, fichiers...
La nature des données est également diverse : binaire, texte, images, son...
Les classes de gestion des flux sont regroupées dans le package java.io.
Les flux de la classe System
1. System.out
Dans les chapitres précédents, les impressions à la console sont faites en utilisant l’instruction :
System.out.println();
out est une propriété de la classe System.
Sa déclaration est :
public static final PrintStream out
C’est une référence de type PrintStream. L’objet désigné par cette référence est instancié au démarrage de l’application et est affecté à la sortie console.
La classe PrintStream dérive de OutputStream via FilterOutputStream :
-
La classe abstraite OutputStream représente un flux de sortie binaire. Les méthodes d’écriture de cette classe envoient un ou plusieurs octets vers une destination de sortie.
-
La classe FilterOutputStream redéfinit toutes les méthodes d’OutputStream.
-
La classe PrintStream définit quelques méthodes d’écritures pratiques, comme print() ou println().
2. System.err
Comme la propriété out, la propriété err de la classe System est de type PrintStream, affectée à la console, et instanciée au démarrage de l’application. Ce flux est spécialisé dans l’affichage des messages d’erreur.
On remarquera parfois un mélange entre les messages d’erreurs et le résultat...
Codage et flux de texte
1. Utilisation de la méthode read() de la classe InputStream
La méthode read() est ainsi décrite dans la documentation de la classe InputStream :
public abstract int read() throws IOException
C’est la méthode la plus rudimentaire pour lire des informations. Cette méthode lit un octet à partir d’une source de données, et en retourne le code.
Le programme suivant montre son utilisation :
public class Saisie1
{
public static void main(String args[]) throws IOException
{
int codeRetour;
System.out.print("Saisir un caractere (puis entrée) : ");
codeRetour = System.in.read();
System.out.println("Octet lu (en hexadécimal) : " +
Integer.toHexString(codeRetour));
}
}
Le résultat de l’exécution de ce programme est le suivant :
System.in est un flux de type InputStream. InputStream est un flux binaire. Cette classe, et ses classes dérivées possèdent des méthodes de lecture d’octets.
Dans l’exemple précédent, quand on tape le caractère € au clavier, le code mis dans la variable codeRetour est 80, valeur correspondant au codage par défaut de la plateforme (Cp1252).
Mais 80 n’est pas le code du caractère € pour Java, qui utilise le codage UTF-16. Dans ce codage, le caractère € à la valeur 20AC.
Pour mettre le code UTF-16 du caractère € tapé au clavier dans une variable, il faut connaître le codage de la plateforme et effectuer une conversion. Ce travail...
Les fichiers
Les fichiers utilisés dans cette section sont stockés dans le dossier : C:\JAVA\Fichiers
1. Classe File
La classe File hérite directement de Object. Un objet de cette classe contient une représentation d’un fichier, indépendante du système d’exploitation. Le constructeur de la classe File prend des paramètres qui permettent de localiser le fichier (dossier, nom du fichier, chemin d’accès). Des méthodes permettent d’obtenir des caractéristiques du fichier désigné.
Exemple
public class TestFile
{
public static void main(String args[]) throws IOException
{
File dossier;
File fichier1, fichier2;
L’objet dossier localise un dossier :
dossier = new File("C:\\JAVA\\Fichiers");
System.out.println(dossier.getAbsolutePath());
L’objet fichier1 localise le fichier "texteOriginal.txt" du dossier :
fichier1 = new File(dossier, "texteOriginal.txt");
System.out.println(fichier1.getAbsolutePath());
L’objet fichier2 localise directement le fichier texteOriginal.txt :
fichier2 = new File("C:\\JAVA\\Fichiers\\texteOriginal.txt");
System.out.println(fichier2.getAbsolutePath()); ...
Les fichiers texte
1. Recopie d’un fichier texte avec changement de codage
a. Utilisation de InputStreamReader et OutputStreamWriter
Dans ce programme, on lit le fichier d’entrée caractère par caractère, et on écrit de même dans le fichier de sortie.
public class CopieTexte1
{
public static void main(String args[]) throws IOException
{
. . .
InputStreamReader entree;
OutputStreamWriter sortie;
int caractere;
dossier = new File("C:\\JAVA\\fichiers");
fichierEntree = new File(dossier, "texteCP1252.txt");
fichierSortie = new File(dossier, "texteUTF8.txt");
Le fichier texte d’entrée est codé en Cp1252, celui de sortie est codé en UTF-8 :
try
{
entree = new InputStreamReader(
new FileInputStream(fichierEntree), "Cp1252");
try
{
sortie = new OutputStreamWriter( ...
Travail pratique : total des notes
1. Objectif
-
Utiliser les flux de texte.
-
Utiliser une classe en cherchant dans la documentation de Java.
2. Sujet
On dispose d’un fichier texte dont les lignes contiennent :
-
Un nom ;
-
Une ou plusieurs notes (entiers) séparées par des points-virgules.
Créer à partir de ce fichier un autre fichier texte contenant une ligne par nom de la forme :
-
Le total des "n" notes de "nom" est de : "total".
Exemple
Pour le fichier d’entrée contenant :
CORNEILLE;0;1;0;10;13;2;1;10
ETOURNEAU;17;2;20;14;19;20;15
MESANGE BLEUE;1;3;2;0;11;18;1;4;2;12;7;3;1
MOINEAU;1;2;0;0;2;1;2;2;1;0;1;0;0;0
HIRONDELLE;0;1;4;0;10
On doit obtenir le fichier de sortie :
Le total des 8 notes de CORNEILLE est de : 37
Le total des 7 notes de ETOURNEAU est de : 107
Le total des 13 notes de MESANGE BLEUE est de : 65
Le total des 14 notes de MOINEAU est de : 12
Le total des 5 notes de HIRONDELLE est de : 15
3. Ressource
La classe StringTokenizer contient des méthodes très pratiques pour isoler les différents mots d’une chaîne de caractères (String). Il est conseillé d’écrire un programme de test des méthodes de cette classe avant de résoudre le problème ci-dessus.
4. Total des notes : proposition de correction
a. Test de quelques méthodes de la classe StringTokenizer
import java.util.*;
import java.io.*;
public class TestStringTokenizer
{
public static void main(String[]...
Travail pratique : fichier texte des contacts
1. Objectif
-
Utiliser les flux de texte.
-
Créer une classe Contact : un objet de cette classe permet de stocker des informations correspondant à un contact.
-
Utiliser une classe de l’API Java en cherchant dans la documentation. Cette utilisation permet de revoir la notion d’interface.
2. Sujet
Premièrement, créez avec un éditeur de texte un fichier de contacts nommé "contacts.txt" composé de lignes de six champs séparés par des ; (point-virgule).
Exemple
125;FAUVETTE;17, impasse de l'egalite;77000;MELUN;1
314;FAUCON;Avenue du Verdier;66000;PERPIGNAN;4
147;SITELLE;Rue des 4 fennecs;66000;PERPIGNAN;3
. . .
Ensuite, créez un programme permettant :
-
Lire ce fichier, stocker les enregistrements lus dans une ArrayList d’objets Contact, dont les propriétés sont :
private Integer numero;
private String nom;
private String adresse;
private String codePostal;
private String ville;
private Integer codeSecteur;
-
Trier l’ArrayList par ordre de numero.
Il existe une méthode sort() dans la classe Collections capable de trier les objets qui implémentent Comparable.
-
Recopier l’ArrayList triée dans un fichier texte "contactsTries.txt". Les lignes de ce nouveau fichier ont la même structure que celles de "contacts.txt".
3. Exemple d’exécution
Fichier contacts.txt :
125;FAUVETTE;17, impasse de l'egalite;77000;MELUN;1
314;FAUCON;Avenue du Verdier;66000;PERPIGNAN;4
147;SITELLE;Rue des 4 fennecs;66000;PERPIGNAN;3
100;CORBEAU FREUX;1, rue Barbe;94000;CRETEIL;1
110;PIE GRIECHE;100, avenue Montaigne;75008;PARIS;2
217;AVOCETTE;123, avenue du general De Gaulle;92000;NANTERRE;1
Fichier ContactsTries.txt :
100;CORBEAU FREUX;1, rue Barbe;94000;CRETEIL;1
110;PIE GRIECHE;100, avenue Montaigne;75008;PARIS;2
125;FAUVETTE;17, impasse de l'egalite;77000;MELUN;1
147;SITELLE;Rue des 4 fennecs;66000;PERPIGNAN;3
217;AVOCETTE;123, avenue du general De Gaulle;92000;NANTERRE;1
314;FAUCON;Avenue du Verdier;66000;PERPIGNAN;4
4. Fichier texte des contacts : proposition de correction
a. Logique du programme
-
Le programme commence par une boucle de création...
Les fichiers binaires
1. Classes DataInputStream, DataOutputStream
a. Hiérarchie des flux d’entrée (extrait)
La classe FileInputStream ne dispose que de méthodes read() permettant de lire un octet ou un tableau d’octets.
La classe DataInputStream possède des méthodes de lecture des types primitifs, telles que : readInt(), readFloat(), readDouble()…
b. Hiérarchie des flux de sortie (extrait)
La classe FileOutputStream ne dispose que de méthodes write() permettant d’écrire un octet ou un tableau d’octets.
La classe DataOutputStream possède des méthodes d’écriture des types primitifs, telles que : writeInt(), writeFloat(), writeDouble()…
c. Création d’un fichier binaire d’entiers (int)
public class CreationBinaire
{
public static void main(String args[]) throws IOException
{
. . .
DataOutputStream sortie;
int n;
. . .
fichierSortie = new File(dossier, "fichier.dat");
try
{
Le constructeur de DataOutputStream prend un OutputStream en paramètre :
sortie = new DataOutputStream(new FileOutputStream(fichierSortie));
try
{
System.out.print("Entrer un entier : ");
n = Clavier.readInt();
while (true)
{
sortie.writeInt(n);
System.out.print("Entrer un entier : ");
n = Clavier.readInt();
}
}
catch (NumberFormatException...
Travail pratique : fichier binaire des contacts
1. Objectif
Le but est de lire en Java un fichier binaire écrit en langage C.
2. Le fichier binaire contacts.dat
Le fichier contacts.dat a été écrit par un programme C.
Chaque enregistrement de ce fichier correspond à une variable de type CONTACT.
Le programme C suivant affiche la taille d’une variable de type CONTACT, en nombre d’octets :
typedef struct
{
int numero;
char nom[21];
char adresse[51];
char codePostal[6];
char ville[21];
int codeSecteur;
} CONTACT;
int main()
{
printf("Taille enreg : %d\n", sizeof(CONTACT));
return 0;
}
Voici le résultat de l’exécution de ce programme :
La structure a un octet de plus que le total des longueurs de ses membres (4 + 21 + 51 + 6 + 21 + 4 = 107). En effet, le total des longueurs des chaînes placées avant l’entier codeSecteur est égal à 99. Un entier est placé en mémoire sur un octet dont l’adresse est un multiple de 4. Il y a donc entre le dernier caractère de la chaîne ville et le premier octet de codeSecteur un "trou" de 1 octet, dont il faut tenir compte pour la lecture du fichier en Java.
3. Données numériques en C et en Java
Les données numériques ne sont pas codées de la même façon en C et en Java (les octets de poids fort et de poids faible sont inversés).
Ainsi, l’entier 100 est codé :
-
64 00 00 00 en C ;
-
00 00 00 64 en Java.
Il faut tenir compte de cette différence pour la lecture du fichier en Java.
4. La classe Fichier (package utilitairesMG.divers)
a. Diagramme de classes
-
La classe Fichier hérite de la classe RandomAccessFile, ce qui permet d’en utiliser toutes les méthodes.
-
Elle facilite l’usage de fichiers binaires constitués d’enregistrements de taille fixe créés en C. Les chaînes...