Flots et Sérialisation des objets. Qu'est-ce qu'un flot? Stream Un objet capable de transférer une...
Transcript of Flots et Sérialisation des objets. Qu'est-ce qu'un flot? Stream Un objet capable de transférer une...
Flots et
Sérialisation des objets
Qu'est-ce qu'un flot? Stream
Un objet capable de transférer une suite d'octets
• soit d'une source externe vers le programme
• soit du programme vers une cible externe
Flot d'entrée (ou de lecture)
Flot de sortie (ou d’écriture)
source programmeclavier,fichier,réseau ...
cible programmeécran,fichier,réseau,imprimante ...
La jungle des flots ( 60 classes en java 2)
• Flots binaires
Package java.io aussi java.util.zip (…)
Information transmise telle quelleoctet par octet
• Flots de texte
Information subit une transformation("formatage") pour passer du codage UNICODEutilisé en java au format texte de la machine hôteet inversement
• par un flot binaire
Exemple : écrire des caractères dans un fichier
• par un flot de texte
Flot de sortie
programme fichier
Car UNICODEsur 2 octets
ces 2 octets
Car UNICODEsur 2 octets
Car code localsur 1 octet
cet octet
'\n' Car LF UNIXCar CR et LF MS-DOS
Le fichier obtenu est lisible par un éditeur de texte
Flots binaires
InputStream OutputStream
Manipulent des octets ou tableaux d'octets
Attention, entêtes des méthodes trompeuses
Par exemple, dans InputStream :public abstract int read() throws IOException
lit un seul octet stocké dans un int (0..255) ou -1 si rien lu
Flots binaires utilisés
InputStream OutputStream
Manipulent des octets
DataInputStream DataOutputStream
Lire et écrire des types primitifs + String
FileInputStreamPermettent d'associer un flot binaire à un fichiermais ne possèdent que des méthodes (de lecture ou d’écriture) de bas niveau
FileOutputStream
abstraites
On "branche" donc des flots sur des flots
Exemple : écrire dans un fichier
DataOuptutStream
programme fichier
int,float,char,… String
FileOutputStream
DataOutputStream fs = new DataOuputStream(new FileOuputStream(“test.bb"));
fs.writeChars(“la chaine a ecrire”);………fs.close();
Flots de texte
Reader Writer
Manipulent des caractères(UNICODE format hôte)
abstraites
InputStreamReader InputStreamWriter
FileReader
Permettent d'associer un flot de texte à un fichier
FileWriter
En pratique on utilise
Pour lire :
BufferedReader méthode readLine()
Pour écrire :
BufferedWriter méthodes write (String) newLine()
PrintWriter méthodes print println
pour écrire tous les types primitifs + String
Qu'on branche sur des flots de plus bas niveau
BufferedReader fc = new BufferedReader(new InputStreamReader(System.in));
String chaineLue = fc.readline();
int i = Integer.parseInt(chaineLue);
Depuis la version 5, on a aussi la classe Scanner :
Scanner sc = new Scanner(System.in);
int i = sc.nextInt();
Exemple : lire un entier tapé au clavier
BufferedReader ff = new BufferedReader (new FileReader ("essai.txt"));
// Lecture du fichier "essai.txt"String s = ff.readLine();
/* readLine() retourne :la ligne lue jusqu'au retour chariot
(lu mais non retourné) donc une chaîne vide si la ligne n’a qu'un RC la valeur null s'il n'y a rien à lire */
while (s!= null){ System.out.println(s);//affichage
console s = ff.readLine();}
ff.close();
Exemple : lire un fichier texte et l’afficher (console)
BufferedReader fc = new BufferedReader (new InputStreamReader (System.in));
BufferedWriter ff = new BufferedWriter (new FileWriter ("essai.txt"));
System.out.println("Entrez des lignes
(Return pour terminer)");String s = fc.readLine();while (s.length() != 0){ ff.write(s); // TQ pas chaîne vide ff.newLine();
s = fc.readLine();}ff.close();
Exemple : créer un fichier texte par lecture au clavier
Et les objets?
Les flots que nous venons de voir permettent de manipuler des :
variables ou valeurs de type primitif
tableaux de caractères
chaînes de caractères (String)
Les Objets autres que des String?
Lecture/écriture d’objets
• Méthode « artisanale »
Ecriture : décomposer l’objet à sauvegarder jusqu’à obtenir des données de type primitif ou des String
Lecture : reconstruire un objet (de la bonne classe !)à partir des données de type primitif ou des String lues
• Méthode automatique : sérialisation
(Attention : sauvegarde au format binaire uniquement)
Principe : décomposition d’un objet jusqu’à arriver à des données de type primitif ou String
Objet od’une classe C
Objet o1 d’une classe C1
Objet o2 d’une classe C2
int i
Quelque part, un objet flot a été créé
sauver(flot){ o1.sauver(flot) o2.sauver(flot) flot.écrire(i)}
Classe C
Exemple : Minidraw (éditeur graphique)
Fenêtre fenêtre principalePanneau panneau CollectionFigures collection de figures
qui encapsule un ArrayList
ArrayList<Figure> encapsule un tableau de figures
Figure classe racine des figuresRect une sorte de figureRectPlein d’autres sortes de figuresOvale … OvalePlein…
Les classes
Sauver un dessin ? = sauver la collectionde Figures
Graphe de décomposition de la collection de figures
monDessinCollectionFigures
tabArrayList<Figure>
TFigure[] Rect
Ovale
RectPlein
compteur int
x int y int …………On décompose l’objet jusqu’à arriver à
des données de type primitif ou des String
Le graphe de décomposition peut être plus complexe qu'une arborescence
Pourquoi on dit « sérialisation »
Que faudrait-il sauvegarder pour pouvoir reconstituer le dessin ?
compteur "Rect" x y Lh Lv colTrait "Oval" x y Lh Lv colTrait"RectPlein" x y Lh Lv colTrait colFond
monDessinCollectionFigures
tabArrayList<Figure>
TFigure[] Rect
Ovale
RectPlein
compteur int
x int y int …………
Où seraient implémentées les méthodes ?
- Quelque part , créer un flot associé à un fichier Méthode sauve(flot) dans CollectionFigures
- écrire le nombre de figures (compteur)- appeler une méthode « sauve » pour chaque figure
Méthode sauve(flot) d’une classe de figure :
- écrit le « type » - écrit les attributs définis dans cette classe- appelle la méthode super.sauve(flot) pour les attributs dont elle hérite
compteur "Rect" x y Lh Lv colTrait "Oval" x y Lh Lv colTrait"RectPlein" x y Lh Lv colTrait colFond
– Sérialisation –Méthode "automatique"
public final void writeObject(Object obj)
throws IOException
Classe java.io.ObjectOutputStream
public final Object readObject() throws OptionalDataException, ClassNotFoundException, IOException
Classe java.io.ObjectInputStream
• Ces classes permettent aussi de manipuler des types primitifs (méthodes writeInt, readInt, …)
•Les tableaux sont des objets
• Ces méthodes ne s'appliquent qu'à des objets sérialisables
= dont la classe implémente l'interface java.io.Serializable (interface "marqueur")
• La propriété d’être sérialisable s'hérite : si une classe implémente une interface, ses sous-classes aussi
• Prenons le graphe de décomposition de l'objet : tous les objets du graphe doivent être sérialisables
(sinon NotSerializableException)
Quelles classes doivent implémenter l’interface Serializable ?
CollectionFigures ArrayList (c’est le cas) Figure
monDessinCollectionFigures
tabArrayList<Figure>
TFigure[] Rect
Ovale
RectPlein
compteur int
x int y int …………
Exemple de la sauvegarde
et de la restauration
d’une collection de figures
en détails
La barre de menu est ajoutée à la fenêtre JMenuBar Jmenu JMenuItem
A l’entrée de menu “sauver” on associe un écouteur d’une classe anonyme, dont la méthode actionPerformed appelle la méthode sauve() de la fenêtre
Rappel : la sélection d’une entrée de menu se gère comme une action sur bouton
Même principe pour “restaurer” méthode restaure() de la fenêtre
Méthode sauve() de la fenêtre
- choix d'un nom de fichier Fic (par boîte de dialogue)- demande à panneau de sauver le dessin dans le fichier de nom Fic
panneau.sauveDessin(Fic);
Méthode restaure() de la fenêtre
- choix d'un nom de fichier Fic (par boîte de dialogue)- demande à panneau de restaurer le dessin depuis le fichier de nomFic
panneau.restaureDessin(Fic);
public void sauveDessin (File Fic) {
ObjectOutputStream flotS = new ObjectOutputStream
(new FileOutputStream (Fic));
flotS.writeObject(monDessin);
flotS.close();
}
Classe Panneau Gère des infos sur un fichier
Que faire de l’exception (IOException) susceptible d’être générée par writeObject ?On la retransmet à la méthode appelante (donc méthode sauve de la fenêtre)
throws IOException
Revenons à la classe Fenêtre :
public void sauve()
{ ………………panneau.sauveDessin(Fic);
}
Problème : “throws IOException” de sauveDessin
De toutes façons, actionPerformed ne peut pas déclarer “throws IOException” (car l’interface ActionListener nel’a pas prévu et qu’une redéfinition de méthodene peut ajouter des exceptions)
La méthode “sauve” ne peut ignorer cette exception :- la retransmet à la méthode appelante (actionPerformed) - ou la capture et la traite
Donc on capture et traite l’exception si elle survient :
public void sauve()
{ ………………try // surveiller ce bloc d’instructions
{ panneau.sauveDessin(Fic); }catch (IOException e) // capturer l’exception si elle survient
{ // traiter le problème JOptionPane.showMessageDialog (null, “Erreur de sauvegarde”);
}
}
Implémentons maintenant la méthode restaure() de la fenêtre
- choix d'un nom de fichier Fic (par boîte de dialogue)- demande à panneau de restaurer le dessin depuis le fichier de nomFic
panneau.restaureDessin(Fic);
public void restaureDessin (File Fic) { ObjectInputStream flotE = new ObjectInputStream
(new FileInputStream (Fic));
Utiliser flotE.readObject()pour recréer l’objet monDessin
}
Classe Panneau
public void restaureDessin (File Fic) throws IOException,ClassNotFoundException
{ ObjectInputStream flotE = new ObjectInputStream
(new FileInputStream (Fic));
Object o = FlotE.readObject(); monDessin = (CollectionFigures) o;
flotE.close();
// demander l’appel de paintComponent repaint();
}
Classe Panneau
Dans la classe Fenêtre, il faut traiter les exceptions pouvant être générées par restaureDessin:
public void restaure()
{ ……………… panneau.restaureDessin(Fic); }
{ ………………try // surveiller ce bloc d’instructions
{ panneau. restaureDessin(Fic); }catch (Exception e) // capturer tout type d’exception !!
{ // on fait le service minimum JOptionPane.showMessageDialog (null, “Erreur de restauration”);
}}
Résumé
Entrée de menu« Sauver » Écouteur.actionPerformed(…)
sauve()
Choix Ficpanneau.sauveDessin(Fic)
sauveDessin(Fic)
writeObject(monDessin)
PANNEAU
FENETRE
Suite d’appels similaire pour « Restaurer »
Choisir un fichier
File Fic = null;JFileChooser chooser = new JFileChooser();
int rep = chooser.showSaveDialog(this);/* affiche une boîte de dialogue permettant de choisir un fichier existant ou nouveau */if (rep == JFileChooser.APPROVE_OPTION) Fic = chooser.getSelectedFile();
Pour la sauvegarde
Pour la restauration : chooser.showOpenDialog
/* affiche une boîte de dialogue permettant de choisir un fichier existant */
Indiquer le parent de la boîteou null
Conclusion sur la sérialisation
Avantages
• Automatique
• Permet de gérer facilement des objets complexes
Inconvénient
Flots binaires : fichiers pas lisibles
[Suite : application au TP Same]
Quels fichiers dans le TP « Same » ?
• Sauvegarde et restauration d’une configuration initiale
- que sauvegarder ? La matrice de pions ? mécanisme de sérialisation Une matrice de couleurs (ou d’entiers) ? méthode « artisanale » Juste le « seed » (pour générer la même série d’entiers) sauvegarder un entier (de type long) utiliser System.currentTimeMillis() pour générer un seed
- n’autoriser la sauvegarde qu’en début de partie voir dans JMenuItem : public void setEnabled(boolean b)
• Sauvegarde et affichage des x meilleurs scores
- on gère des couples (nom, score) sans doute commode de créer une classe ScoreItem et de gérer un tableau de ScoreItem
- fichier binaire plutôt que texte ? (éviterait une modification sauvage des scores) le mécanisme de sérialisation est alors utilisable
- à la fin d’une partie, mise à jour éventuelle du fichier des scores
- afficher en permanence les x meilleurs scores ?