File Handling

Télécharger au format pdf ou txt
Télécharger au format pdf ou txt
Vous êtes sur la page 1sur 58

1

Chapitre

Les entrées sorties


Entrées Sorties
2

 Un programme a souvent besoin d'échanger des informations, que ce soit


pour recevoir des données d'une source ou pour envoyer des données vers un
destinataire.

 La source et la destination de ces échanges peuvent être de natures


multiples : un fichier, une socket réseau, un autre programme, etc ...
 De la même façon, la nature des données échangées peut être diverse : du
texte, des images, du son, etc ...
Notion des flux
3

 Les flux (streams en anglais) permettent d'encapsuler ces processus d'envoi et de


réception de données. Les flux traitent toujours les données de façon
séquentielle.
 En Java, les flux peuvent être divisés en plusieurs catégories :
◼ les flux d'entrée (input stream) et les flux de sortie (output stream)
◼ les flux de traitement de caractères et les flux de traitement d'octets
 Java définit des flux pour lire ou écrire des données mais aussi des classes qui
permettent de faire des traitements sur les données du flux. Ces classes doivent
être associées à un flux de lecture ou d'écriture et sont considérées comme des
filtres. Par exemple, il existe des filtres qui permettent de mettre les données
traitées dans un tampon (buffer) pour les traiter par lots.
 Toutes ces classes sont regroupées dans le package java.io
Flux d’octets et Flux de caractères (1)
4

Entrée
Ex : Nous sommes la destination

Sortie
Ex : Nous sommes la source
Flux d’octets et Flux de caractères (2)
5
 Les flux sont décomposés en deux grandes familles
◼ Flux d’octets
◼ classes abstraites InputStream et OutputStream et leurs sous-
classes concrètes respectives
◼ Flux de caractères
◼ classes abstraites Reader et Writer et leurs sous-classes
concrètes respectives

Flux d'octets Flux de caractères


Flux d'entrée InputStream Reader
Flux de sortie OutputStream Writer
Flux d’octets et Flux de caractères (3)
6

 les sous-classes de Reader sont des types de flux en lecture sur des
ensembles de caractères
 les sous-classes de Writer sont des types de flux en écriture sur des ensembles
de caractères
 les sous-classes de InputStream sont des types de flux en lecture sur des
ensembles d'octets
 les sous-classes de OutputStream sont des types de flux en écriture sur des
ensembles d'octets
Flux d’octets et Flux de caractères (4)
7

Pour le préfixe, il faut distinguer les flux et les filtres.


Pour les flux, le préfixe contient la source ou la destination selon le sens du
flux.
Flux d’octets et Flux de caractères (5)
8

Pour les filtres, le préfixe contient le type de traitement qu'il effectue. Les filtres
n'existent pas obligatoirement pour des flux en entrée et en sortie.
Flux d’octets et Flux de caractères (6)
9
La package java.io définit ainsi plusieurs classes :

Flux en lecture Flux en sortie


BufferedReader BufferedWriter
CharArrayReader CharArrayWriter
FileReader FileWriter
Flux de caractères InputStreamReader OutputStreamWriter
LineNumberReader
PipedReader PipedWriter
PushbackReader
StringReader StringWriter
BufferedInputStream BufferedOutputStream
ByteArrayInputStream ByteArrayOutputStream
DataInputStream DataOuputStream
Flux d’octets FileInputStream FileOutputStream
ObjectInputStream ObjetOutputStream
PipedInputStream PipedOutputStream
PushbackInputStream PrintStream
SequenceInputStream
Flux d’octets et Flux de caractères (7)
10

 E/S octet vs E/S Char

• Si on traite des caractères, on utilise Reader/Writer, sinon InputStream/OutputStream


• À la base, le flux est en octets (mais Reader/Writer le cache)
Entrée et Sortie standard
11

 Sortie standard (principalement la console):


 Normal
System.out et System.err
System.out.println(…) sont des attributs de la classe System
de type PrintStream
 Erreur
System.err.println(…)

Entrée standard (principalement le clavier):


InputStreamReader cin = new
InputStreamReader(System.in);
System.in
est un attribut de type InputStream (= flux
Byte) de la classe System.
InputStreamReader permet de l’utiliser
comme un flux Character
Exemple : lire une ligne sur l’entrée standard
12

import java.io.*;
class InOut {
public static void main(String args[]) throws IOException {
BufferedReader entreeClavier = new BufferedReader(
new InputStreamReader(System.in));
System.out.println ("Saisissez une phrase :");
String saisie = entreeClavier.readLine();
System.out.println ("Merci !");
System.out.println ("Votre phrase est : ");
System.out.println (saisie);
}
}
Formater la sortie
13

Personnaliser le format de sortie :


– Alternative aux méthodes print et println.
– Pour plus de détail voir la javadoc format
System.out.println("Pi vaut " + Math.PI);
> Pi vaut 3.141592653589793
System.out.format("Pi vaut approximativement %.2f%n",Math.PI);
> Pi vaut approximativement 3,14
On peut être même plus spécifique DecimalFormat de java.text.*
Formater la sortie
14
import java.text.DecimalFormat; // light speed.
public class Test { long lightSpeed = 299792458;
public static void main(String[] args)
{ // Display use scientific counting method and
// PI //take five decimal places.
double pi=3.1415927; df = new DecimalFormat("#.#####E0");
// Take one integer. System.out.println(df.format(lightSpeed));
DecimalFormat df = new DecimalFormat("0"); //2.99792E8
System.out.println(df.format(pi)); // 3
// Use scientific counting method to show two
//Take one integer and two decimal //integers and four decimal places.
df = new DecimalFormat("0.00"); df = new DecimalFormat("00.####E0");
System.out.println(df.format(pi)); // 3.14 System.out.println(df.format(lightSpeed));
//29.9792E7
// Take two integers and three decimals, and the inadequacies
//for integer are filled with 0. //Each three integer are separated by commas.
df = new DecimalFormat("00.000"); df = new DecimalFormat(",###");
System.out.println(df.format(pi));// 03.142 System.out.println(df.format(lightSpeed));
//299,792,458
// Take all the integers.
df = new DecimalFormat("#"); //Embed formatting in text.
System.out.println(df.format(pi)); // 3 df = new DecimalFormat("The speed of light is
,### meters per second.");
// Count as a percentage and take two decimal places. System.out.println(df.format(lightSpeed));
df = new DecimalFormat("#.##%"); }
System.out.println(df.format(pi)); //314.16%
}
Formatter la sortie
15

# Un chiffre, les zéros non significatifs sont omis.


. Marque le séparateur décimal
, Séparateur de groupement de marques (par exemple, séparateur de milliers)

E Marque la séparation de la mantisse et de l'exposant pour les formats exponentiels.


; Sépare les formats
- Marque le préfixe numérique négatif
% Multiplie par 100 et affiche le nombre en pourcentage

? Multiplie par 1000 et affiche le nombre selon mille

Symbole monétaire : remplacé par le signe monétaire de la langue locale. Permet également au
¤ formatage d'utiliser le séparateur décimal monétaire au lieu du séparateur décimal normal. ¤¤ permet
au formatage d'utiliser des symboles monétaires internationaux.

X Marque un caractère à utiliser dans le préfixe ou le suffixe du numéro

' Marque un guillemet autour des caractères spéciaux dans le préfixe ou le suffixe du nombre formaté.
Flux d’octets et Flux de caractères (6)
16
Flux Buffered
17

• L’usage de flux d’octets ou de caractères peuvent être coûteux


ex : accès au disque dur, connexion réseau, ...
• Les flux bufferisés lisent les données par blocs
▪ buffer = tampon
▪ une quantité de données est chargée en une fois dans une zone de mémoire
plus rapide d’accéder
• Les buffers se branchent comme des convertisseurs sur les flux standards :
in = new BufferedReader( new FileReader("original.txt"));
out = new BufferedWriter( new FileWriter("copie.txt"));

Flux Character
Flux bufferisés
Les flux de caractères
18

 Ce sont des sous-classes de Reader et Writer


 Ces flux utilisent le codage de caractères Unicode
 Exemples
◼ conversion des caractères saisis au clavier en caractères dans le codage par
défaut

InputStreamReader in = new InputStreamReader (System.in);

Conversion des caractères d’un fichier avec un codage explicitement indiqué

InputStreamReader in = new InputStreamReader (


new FileInputStream ("chinois.txt"), "ISO2022CN");
Gestion des fichiers (1)
19

 La gestion de fichiers proprement dite se fait par l'intermédiaire de la


classe File
 Cette classe possède des méthodes qui permettent d'interroger ou d'agir
sur le système de gestion de fichiers du système d'exploitation
 Un objet de type classe File peut représenter un fichier ou un répertoire
Gestion des fichiers (2)
20

 Voici un aperçu de quelques constructeurs et méthodes de la classe File :


◼ File (String name)

◼ File (String path, String name)

◼ File (File dir, String name)

◼ boolean isFile( ) / boolean isDirectory( )

◼ boolean mkdir( )

◼ boolean exists( )

◼ boolean delete( )

◼ boolean canWrite( ) / boolean canRead( )

◼ File getParentFile( )

◼ long lastModified( )
Gestion des fichiers (3)
21
Gestion des fichiers (4)
22
Gestion des fichiers (5)
23
import java.io.*; Les objets et classes relatifs à
public class Listeur la gestion des fichiers se
{ trouvent dans le package
java.io
public static void main(String[] args)
{ A partir du chemin d'un dossier ou
Listeur.litrep(new File(".")); d'un fichier, on peut créer un objet
} File : ici on va lister le répertoire
public static void litrep(File rep) courant (« . »)
{
if (rep.isDirectory()) Les méthodes isFile() et
{ //liste les fichiers du répertoire isDirectory() permettent de
déterminer si mon objet File est
String[] t=rep.list();
une fichier ou un répertoire
for (int i=0;i<t.length;i++)
System.out.println(t[i]);
}
}
}
Gestion des fichiers (6)
24

import java.io.*;
public class Listeur
{
Le nom complet du fichier
public static void main(String[] args) est rep\fichier
{ litrep(new File( "c:\\"));}

public static void litrep(File rep)


{ Pour chaque
File r2; fichier,
on regarde s'il est
if (rep.isDirectory())
un répertoire.
{String t[]=rep.list();
for (int i=0;i<t.length;i++)
{ Si le fichier est un
r2=new File(rep.getAbsolutePath()+"\\"+t[i]); répertoire
if (r2.isDirectory()) litrep(r2); litrep s'appelle
else System.out.println(r2); récursivement
}}
}}
25

Exemples
FileInputStream et FileOutputStream (1)
26

 C'est par le biais des objets FileInputStream et FileOutputStream que nous allons
pouvoir :
◼ lire un fichier d’octets;
◼ écrire des octets dans un fichier.
 Ces classes héritent des classes abstraites InputStream et OutputStream, présentes
dans le package java.io.
FileInputStream et FileOutputStream (2)
27
FileInputStream et FileOutputStream (3)
28
FileInputStream et FileOutputStream (4)
29
BufferedInputStream et BuffreredOutputStream (1)
30

 BufferedInputStream enveloppe à son intérieur un objet InputStream, qui lit


automatiquement les données de l'origine (un fichier, par exemple) et les
stocke dans buffer (la mémoire tampon) de BufferedInputStream.
 BufferedInputStream remplace les méthodes qui héritent de sa classe
parentale, comme read(), read(byte []),... pour s'assurer qu'elles manipuleront
les données de la buffer plutôt que de l'origine (un fichier, par exemple).
BufferedInputStream et BuffreredOutputStream (1)
31
BufferedInputStream et BuffreredOutputStream (2)
32
BufferedInputStream et BuffreredOutputStream (3)
33
BufferedInputStream et BuffreredOutputStream (4)
34
File(Writer/Reader) et Print(Writer/Reader) (1)
35

PrintWriter(Writer)
 Créer un objet PrintWriter pour
imprimer des données formatées dans
un autre Writer.

PrintWriter(File file)
 Créer un objet PrintWriter pour
imprimer des données formatées dans
un fichier.
 Si BufferedWriter participe à la
structure de PrintWriter, les données
seront écrites temporairement dans
buffer (de BufferedWriter)
File(Writer/Reader) et Print(Writer/Reader) (2)
36
BufferedWriter – BufferedReader (1)
37

 La classe Java BufferedWriter (java.io.BufferedWriter) fournit une mise en


mémoire tampon aux instances de Writer. La mise en mémoire tampon peut
accélérer considérablement les E/S. Plutôt que d'écrire un caractère à la fois
sur le réseau ou le disque, le BufferedWriter écrit un bloc plus grand à la fois.
C'est généralement beaucoup plus rapide, en particulier pour l'accès au disque
et les grandes quantités de données.
BufferedWriter – BufferedReader (2)
38

import java.io.*;
public class Ecrire
{
public static void main(String[] args)
A partir du chemin d'un dossier ou
{ d'un fichier, on peut créer un objet
try FileWriter puis à partir ce celui-ci,
{ on crée un BufferedWriter
FileWriter fw=new
FileWriter("c:\\temp\\essai.txt");
BufferedWriter bw= new BufferedWriter(fw);
bw.write("Ceci est mon fichier");
bw.newLine();
bw.write("Il est à moi...");
bw.close();
} Attention, lorsque l'on a
écrit, il ne faut pas oublier
catch (Exception e)
de fermer le fichier
{ System.out.println("Erreur "+e);}
}}
BufferedWriter – BufferedReader (3)
39

import java.io.*;
public class LireLigne A partir du chemin d'un dossier ou
{ d'un fichier, on peut créer un objet
public static void main(String[] args) FileReader puis à partir ce celui-ci,
{ on crée un BufferedReader
try
{
FileReader fr=new FileReader("c:\\windows\\system.ini");
BufferedReader br= new BufferedReader(fr);
while (br.ready())
System.out.println(br.readLine());
br.close();
}
catch (Exception e) Dans l'objet BufferedReader
{System.out.println("Erreur "+e);} on dispose d'une méthode
} readLine()
}
TRES IMPORTANT
40

vous voulez être sûrs que votre flux est bien


fermé, utilisez la clause finally
ObjectInputStream et ObjectOutputStream (1)
41

 Vous devez savoir que lorsqu'on


veut écrire des objets dans des
fichiers, on appelle ça
la « sérialisation » : c'est le nom
que porte l'action de sauvegarder
des objets !
ObjectInputStream et ObjectOutputStream (2)
42
ObjectInputStream et ObjectOutputStream (3)
43
ObjectInputStream et ObjectOutputStream (4)
44
 Ce qu'il se passe est simple : les données de vos objets sont enregistrées dans le
fichier. Mais que se passerait-il si notre objet Game avait un autre objet au sein
de cette classe.
ObjectInputStream et ObjectOutputStream (5)
45
ObjectInputStream et ObjectOutputStream (5)
46

 Le code ne compile plus ! L’objet Notice n'est pas sérialisable, une erreur
d’exécution est donc levée. Maintenant, deux choix s'offrent à vous :
◼ soit vous faites en sorte de rendre votre objet sérialisable ;
◼ soit vous spécifiez dans votre classe Game que la variable notice n'a pas
à être sérialisée.
 Pour la première option, c'est simple, il suffit d'implémenter l'interface
sérialisable dans notre classe Notice. Pour la seconde, il suffit de déclarer
votre variable : transient ;
ObjectInputStream et ObjectOutputStream (6)
47
Sérialisation (1)
48

La sérialisation d'un objet permet d'envoyer dans un flux les informations sur la
classe et l'état d'un objet pour permettre de le récréer ultérieurement. Elle
permet donc de transformer l'état d'un objet pour permettre sa persistance (en
dehors de la JVM) ou de l'échanger en utilisant le réseau.

L'opération inverse qui consiste à créer une nouvelle instance à partir du résultat
d'une sérialisation s'appelle la désérialisation.
Sérialisation (2)
49

 Cette interface ne définit aucune méthode mais permet simplement de


marquer une classe comme pouvant être sérialisée.
 Tout objet qui doit être sérialisé grâce au mécanisme par défaut doit
implémenter cette interface ou une de ses classes mères doit
l'implémenter.
 Si l'on tente de sérialiser un objet qui n'implémente pas l'interface
Serializable, une exception java.io.NotSerializableException est levée.
 Certains objets ne peuvent pas être sérialisés notamment ceux
dépendants du système d'exploitation : threads, fichiers, ...
 Son utilisation peut engendrer des problèmes de sécurité : sérialisation de
données sensibles, désérialisation d'un objet dont la source est inconnue,
etc.
Sérialisation (3)
50

Il existe plusieurs formats de sérialisation appartenant à deux grandes familles :


• formats binaires : c'est le format par défaut
• formats textes : ils sont plus portables car ils utilisent généralement une
structuration standard (XML, JSON, ...), peuvent être facilement modifiés et
consomment plus de ressources pour être traités
Sérialisation (4)
51

 Tous les champs d'un objet sont sérialisés, y compris ceux de la section
privée.

◼ Problème de sécurité si nous ne voulons pas stocker ces informations

◼ Solution

◼ Chaque attribut critique doit être identifié auparavant avec le mot-


clé : transcient

◼ Méthodes de réécriture writeObjet() et readObject() afin qu'elles


n'enregistrent/lisent que les données souhaitées
La sérialisation est récursive
52

 Lors de la sérialisation d’un objet Serializable, tous les objets

qu’il contient sont sérialisés et ainsi de suite récursivement, aussi


avec les tableaux d’objets (Array, ArrayList, etc).

 Il y a la construction d’un graphe d’objet à sérialiser (“web of


objects” ou “object graph”) qui est parcouru lors de l’étape de
sérialisation.

 La construction et le parcours de ce graphe peut être coûteux.

• Implémenter alors l’interface Externalizable si tout le


contenu d’un objet n’est pas à sérialiser par exemple.
La sérialisation est récursive
53
Serializable Externalizable
L’ interface Serializable est utilisée pour implémenter la L’interface Externalizable est utilisée pour implémenter
sérialisation. Externalization

Serializable est une interface de marqueur, c'est-à-dire qu'elle L'interface Externalizable n'est pas une interface de marqueur et
ne contient aucune méthode. définit donc deux méthodes writeExternal() et readExternal()

L'interface sérialisable transmet la responsabilité de la L'interface externalizable fournit toutes les responsabilités de
sérialisation à JVM et le programmeur n'a aucun contrôle sur sérialisation à un programmeur et, par conséquent, JVM n'a aucun
la sérialisation, et c'est un algorithme par défaut. contrôle sur la sérialisation.

La sérialisation à l'aide d'une interface sérializable a de La sérialisation à l'aide d'une interface externalizable offre de
mauvaises performances. meilleures performances.

La sérialisation par défaut ne nécessite aucun constructeur Un constructeur public sans argument est requis lors de
sans argument. l'utilisation d'une interface externalizable.

Il est difficile d'analyser et de modifier la structure des classes Il est relativement facile d'analyser et de modifier la structure des
car tout changement de structure peut interrompre la classes en raison du contrôle complet de la logique de
sérialisation. sérialisation.

En utilisant une interface sérialisable, nous enregistrons l'objet


Sur la base de nos exigences, nous pouvons enregistrer soit l'objet
total dans un fichier, et il n'est pas possible d'enregistrer une
total, soit une partie de l'objet.
partie de l'objet.

Le mot clé Transient joue ici un rôle important. Le mot clé Transient joue un autre role.
Exemple de Externalizable
54

import java.io.*;
public class Blip3 implements Externalizable {
private int i; private String s;
public Blip3() {
print("Blip3 Constructor"); // is not initialized
}
public Blip3(String x, int a) {
print("Blip3(String x, int a)");
i = a; s = x; // is initialized only in non-default constructor.
}
public void writeExternal(ObjectOutput out) throws IOException {
print("Blip3.writeExternal");
out.writeObject(s); // You must do this
out.writeInt(i); // You must do this
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
print("Blip3.readExternal");
s = (String)in.readObject(); // You must do this
i = in.readInt(); // You must do this
}
}
Exemple de sérialisation
55

On souhaite sérialiser cet objet :


public class Matrix {
int[][] valeurs;
String info;
}

EXERCICE:
1. On souhaite pouvoir sérialiser les objets de cette classe
2. On souhaite limiter la sérialisation uniquement au champs info et aux
valeurs dans la diagonale de la matrice
Exemple de séerialisation
56

On ne souhaite sérialiser que les valeurs de la diagonale :


public class Matrix implements Externalizable {
int[][] valeurs;
String info;
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();// serialise uniquement info
// Sauvegarde explicite des valeurs de la diagonale
for (int i = 0; i < nbValeurs; i++)
s.writeInt(valeurs[i][i]);
}
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException
{
s.defaultReadObject(); // récupération de info
// Récupération des valeurs de la diagonale
for (int i = 0; i < nbValeurs; i++)
valeurs[i][i] = s.readInt();
}
}
Application
57

 Cet exercice porte sur l'utilisation d'un lecteur de


fichier. Il s'agit de compter le nombre
d'occurrence d'un mot donné dans un fichier
donné. Le nom du fichier et le mot seront
indiqués sur la ligne de commande.
Correction
58
import java.io.*;
import java.util.*;

class NbOcc
{
public static void main (String[] argv) throws IOException
{
int nombre=0;
String ligne;
StringTokenizer st;
String mot=new String(argv[1]);
BufferedReader entree =new BufferedReader
(new FileReader(argv[0]));

while((ligne=entree.readLine())!=null)
{
st=new StringTokenizer(ligne,".;() =[]");
while(st.hasMoreTokens())
if (mot.equals(st.nextToken())) nombre++;
}
System.out.println("Le mot "+mot+" figure "+nombre+" fois");
}
}

Vous aimerez peut-être aussi