Badr Benmammar badr.benmammar@gmail.com Master Réseaux et Systèmes Distribués (RSD) Algorithmique des systèmes et applications réparties (pré requis) Badr Benmammar badr.benmammar@gmail.com
Plan - Pré requis Exception Gestion des fichiers Capturer une exception : try … catch Propager une exception : throws Propager et capturer : throws et try … catch Générer une exception : throw Générer et capturer une exception : throw et try … catch Exceptions personnalisées : générer et capturer ses propres exceptions Gestion des fichiers Classe File Quelques flots : FileReader : lire un fichier caractère par caractère FileWriter : écrire des caractères dans un fichier PrintWriter : println et print dans un fichier BufferedReader : rechercher un mot dans un fichier Sérialisation : enregistrer et restaurer des objets L’interface Serializable ObjectOuputStream : écrire des objets dans un fichier ObjectInputStream : lire des objets à partir d’un fichier
Exception
Exception public class Equation1 { private int a, b; public Equation1(int a, int b) { this.a=a; this.b=b; } public void afficher() { System.out.println(a+" * X = "+b); int solution() { return b/a; // ligne 10 public static void main(String args[]) { int valeurA=Integer.valueOf(args[0]).intValue(); int valeurB=Integer.valueOf(args[1]).intValue(); Equation1 equa = new Equation1(valeurA,valeurB); equa.afficher(); int x = equa.solution();// ligne 17 System.out.println("résultat : X = "+x); java Equation1 0 2 0 * X = 2 Exception in thread "main" java.lang.ArithmeticException: / by zero at Equation1.solution(Equation1.java:10) at Equation1.main(Equation1.java:17)
Exception L'instruction division entière peut lever une exception: ArithmeticException (erreur d'exécution) . Une exception est un message envoyé lors d'une erreur à l'exécution. Ce message contient des informations sur l'erreur qui s'est produite. Java stoppe l'exécution du code là où l'exception a été levée et envoie le "message" exception. Sans capture du message exception, celui provoque l'arrêt successif des méthodes appelées jusqu'à la machine JVM qui vous indique l'erreur produite avec beaucoup de détails issus des informations du message. Les exceptions sont organisées en classe, Java contient une classe nommée Exception, où sont répertoriés différents cas d'erreurs.
Capturer une exception public class Equation2 { private int a, b; public static void main(String args[]) { int valeurA= Integer.valueOf(args[0]).intValue(); int valeurB= Integer.valueOf(args[1]).intValue(); Equation2 equa = new Equation2(valeurA,valeurB); equa.afficher(); int x = equa.solution(); System.out.println("résultat : X = "+x); } public Equation2(int a, int b) { this.a=a; this.b=b; public void afficher() { System.out.println(a+" * X = "+b); } int solution( ) { int x; try { x = b/a; } catch (ArithmeticException e) { x = -1; return x; L'instruction "try ... catch" permet de capturer des exceptions : dès qu'une exception est levée dans le corps de try, le traitement de ce corps est terminé. catch définit le traitement pour les ArithmeticException capturées. L'exécution continue normalement en reprenant après le bloc try-catch. Ce mécanisme permet de traiter les erreurs et d'empêcher qu'elle n'arrête l'application en cours. L'exception a été capturée et traitée : x = -1. EXECUTION: java Equation2 0 2 0 * X = 2 résultat : X = -1
Propager une exception public class Equation3 { private int a, b; public Equation3(int a, int b) { this.a=a; this.b=b; } public void afficher() { System.out.println(a+" * X = "+b); int solution() throws ArithmeticException { return b/a; public static void main(String args[]) { int valeurA= Integer.valueOf(args[0]).intValue(); int valeurB= Integer.valueOf(args[1]).intValue(); Equation3 equa = new Equation3(valeurA,valeurB); equa.afficher(); int x = equa.solution(); System.out.println("résultat : X = "+x); }
Propager et capturer une exception public static void main(String args[]) { int valeurA= Integer.valueOf(args[0]).intValue(); int valeurB= Integer.valueOf(args[1]).intValue(); Equation3 equa = new Equation3(valeurA,valeurB); equa.afficher(); try { int x = equa.solution(); System.out.println("résultat : X = "+x); } catch (ArithmeticException e) { System.out.println ("pas de solution"); } public class Equation3 { private int a, b; public Equation3(int a, int b) { this.a=a; this.b=b; } public void afficher() { System.out.println(a+" * X = "+b); int solution() throws ArithmeticException { return b/a; La déclaration "throws" permet d'indiquer que la méthode est susceptible de lever une exception : ici ArithmeticException, qu'elle ne capture pas par un try-catch. ArithmeticException sera propagée/transmise à la méthode appelante si elle est levée, donc il faut que les méthodes qui appelle la méthode solution mettent éventuellement en place un mécanisme de capture try-cath ou qu'elles propagent elles aussi l'exception. L'exception ArithmeticException peut survenir dans la méthode solution puisque sa déclaration l'indique (throws). Lorsqu'elle survient dans solution, elle est propagée jusqu'à une méthode appelante qui la capture et la traite. C'est la méthode main.
(Générer/lever) une exception public class Equation4 { private int a, b; public Equation4(int a, int b) { this.a=a; this.b=b; } public void afficher() { System.out.println(a+" * X = "+b); int solution() { if (a==0) throw new ArithmeticException ("division entière par zéro"); else return b/a; public static void main(String args[]) { int valeurA=Integer.valueOf(args[0]).intValue(); int valeurB=Integer.valueOf(args[1]).intValue(); Equation4 equa = new Equation4(valeurA,valeurB); equa.afficher(); int x = equa.solution(); System.out.println("résultat : X = "+x);
(Générer/lever) une exception L'instruction "throw" (sans s) permet de générer/lever une exception, ici ArithmeticException. De plus, un message d'erreur est ajoutée dans les informations véhiculées par l'exception. Exception in thread "main" java.lang.ArithmeticException: division entière par zéro at Equation4.solution(Equation4.java:10) at Equation4.main(Equation4.java:18) L'instruction throw instancie un objet exception, arrête l'exécution normale des instructions et sauf try-catch propage l'exception.
Générer et capturer une exception public static void main(String args[]) { int valeurA= Integer.valueOf(args[0]).intValue(); int valeurB= Integer.valueOf(args[1]).intValue(); Equation4 equa = new Equation4(valeurA,valeurB); equa.afficher(); try { int x = equa.solution(); System.out.println("résultat : X = "+x); } catch (ArithmeticException e) { System.out.println (e.getMessage()); } public class Equation4 { private int a, b; public Equation4(int a, int b) { this.a=a; this.b=b; } public void afficher() { System.out.println(a+" * X = "+b); int solution() { if (a==0) throw new ArithmeticException ("division entière par zéro"); else return b/a; A la capture d'exception, il est possible d'afficher le message associé en utilisant la méthode getMessage sur l'objet exception. getMessage est une des méthodes de l'objet Exception qui donne des informations sur l'exception. Exécution: java Equation4 0 4 0 * X = 4 division entière par zéro
throws vs throw throws: ce mot clé permet d’ajouter à une déclaration de méthode qu'une exception potentielle sera propagée. Ce mot clé est suivi du nom de la classe qui va gérer l'exception. Ceci a pour but de définir le type d'exception qui risque d'être générée par l'instruction, ou la classe qui précède le mot clé throws. throw: celui-ci permet d'instancier un objet dans la classe suivant l'instruction throws. Cette instruction est suivie du mot clé new ainsi que d'un objet cité avec throws. En fait, il lance une exception, tout simplement.
Exception : résumé JVM provoque l’arrêt successif des méthodes appelées jusqu’à la machine JVM Propager main m2 try … catch Générer try … catch m1 throws Capturer: try … catch Propager : throws Propager et capturer: throws et try … catch Générer: throw Générer et capturer: throw et try … catch try … catch throws throw throw
Exceptions personnalisées public static void main(String args[]) { System.out.println("Donner un nom:"); String nom=Saisie.litexte(); System.out.println("Donner le nombre d'heures:"); int nombreh = Saisie.litentier(); try { Enseignant en = new Enseignant(nom,nombreh); en.afficher ( ); } catch (nombre e) { System.out.println("Attention!!"); } System.out.println("FIN");} public class Enseignant { private String nom; private int nombreh; public Enseignant (String nom, int nombreh) throws nombre { if (nombreh < 0) throw new nombre ( ); else{ this.nom=nom; this.nombreh=nombreh; } public void afficher(){ System.out.println(nom+" " +nombreh+ " heures"); public class nombre extends Exception{ public nombre ( ){ System.out.println ("LE NOMBRE D'HEURES EST NEGATIF!"); }} Objectif: obtenir des messages d'erreurs appropriés à son programme (générer et capturer ses propres exceptions).
Exceptions personnalisées public static void main(String args[]) { System.out.println("Donner un nom:"); String nom=Saisie.litexte(); System.out.println("Donner le nombre d'heures:"); int nombreh = Saisie.litentier(); try { Enseignant en = new Enseignant(nom,nombreh); en.afficher ( ); } catch (nombre e) { System.out.println("Attention!!"); } System.out.println("FIN");} Exécution: Sans exception (nombreh >=0) bb 77 heures FIN Avec exception (nombreh <0) LE NOMBRE D'HEURES EST NEGATIF! Attention!!
Exceptions personnalisées public static void main(String args[]) { System.out.println("Donner un nom:"); String nom=Saisie.litexte(); System.out.println("Donner le nombre d'heures:"); int nombreh = Saisie.litentier(); try { Enseignant en = new Enseignant(nom,nombreh); en.afficher ( ); } catch (nombre e) { System.out.println("Attention!!"); } catch (nom e) { System.out.println ("Attention!!"); System.out.println("FIN"); public class Enseignant { private String nom; private int nombreh; public Enseignant (String nom, int nombreh) throws nombre, nom { if (nombreh < 0) throw new nombre ( ); if (nom.equals ("")) throw new nom(); else{ this.nom=nom; this.nombreh=nombreh; } public void afficher(){ System.out.println(nom+" " +nombreh+ " heures"); public class nom extends Exception{ public nom ( ){ System.out.println ("LE NOM EST VIDE!");}}
Exceptions personnalisées public static void main(String args[]) { System.out.println("Donner un nom:"); String nom=Saisie.litexte(); System.out.println("Donner le nombre d'heures:"); int nombreh = Saisie.litentier(); try { Enseignant en = new Enseignant(nom,nombreh); en.afficher ( ); } catch (nom e) { System.out.println("Attention!!"); } System.out.println("FIN");} Exécution: Sans exception (nom.equals ("") == false) bb 77 heures FIN Avec exception (nom.equals ("") == true) LE NOM EST VIDE! Attention!!
Gestion des fichiers
Gestion des fichiers : classe File import java.io.*; public class Fichier extends File { public Fichier (String nomFichier) { super (nomFichier); } public boolean lirePossible() { return (this.exists()&&this.isFile() &&this.canRead()); public boolean ecrirePossible() { &&this.canWrite()); public String proprietes() { StringBuffer s=new StringBuffer(); if (!this.exists()) s.append ("fichier non existant"); else if (this.isFile()) { s.append ("fichier"); if (this.canRead()) s.append (" acces en lecture"); if (this.canWrite()) s.append (" acces en ecriture"); } else if (this.isDirectory()) s.append ("repertoire"); return new String(s); public String parent() { String nomAbsolu=this.getAbsolutePath(); return nomAbsolu.substring(0, nomAbsolu.lastIndexOf(File.separator)); Avec "/C/Rep/test" comme chemin absolu, le parent est /C/Rep
Gestion des fichiers : classe File Classe Fichier : Permet d'instancier un objet File par le nom (chemin relatif ou absolu) de ce fichier ou répertoire. Permet de savoir si le fichier est accessible en lecture ou écriture. Donne les caractéristiques du fichier ou répertoire. Classe File du package io : Méthodes : boolean exists si le fichier ou répertoire existe. boolean isFile si c'est un fichier. boolean canRead s'il est accessible en lecture. boolean canWrite s'il est accessible en écriture. boolean isDirectory si c'est un répertoire. String getName son nom sans le chemin d'accès. String getAbsolutePath son chemin absolu. Attribut static : separator le séparateur dans les chemins du système de fichier.
Un programme qui liste les propriétés des fichiers passés en argument import java.io.*; public class Fichier1 { public static void main(String[] args) { Fichier fichier; if (args.length==0) { System.out.println (" pas d’arguments ...!"); System.exit(0); } for (int i=0; i<args.length; ++i) { fichier= new Fichier (args[i]); System.out.println(fichier.getName()+" :"); System.out.println(fichier.proprietes()); System.out.println("Le repertoire parent est :"); fichier=new Fichier (args[0]); System.out.println(fichier.parent()); Exécution: java Fichier1 f1.txt f2.java test f1.txt : fichier acces en lecture f2.java : fichier non existant test : fichier acces en lecture acces en ecriture Le repertoire parent est : c:\Test
Flot de lecture Etant donné la quantité d’information d’un fichier, il est peu conseillé voire impossible de le charger d'un bloc dans une variable. Un flot (ou flux) en lecture permet d’y accéder au fer et à mesure : donnée par donnée, "un peu comme un tuyau". Le flot doit être ouvert puis on accède aux données selon la nature du flot : Caractère par caractère. Par blocs de caractère. Avec la gestion d'un tampon. Séquentiellement ou directement à tel position. ..... Ces différents modes expliquent le nombre important de classes de flot en Java. Enfin on le ferme.
Lire un fichier caractère par caractère et l’afficher à l’écran try { FileReader flotLecture = new FileReader (fichier); long longueurFichier= fichier.length(); int dejaLu = 0; char car=0; while (dejaLu < longueurFichier) { car= (char)flotLecture.read(); dejaLu = dejaLu + 1; System.out.print(car); } flotLecture.close(); } catch (IOException e) { System.out.println(" erreur :" + e.toString()); import java.io.*; public class LireFichier1 { public static void main(String[] args) { if (args.length!=1) { System.out.println(" un seul argument SVP !"); System.exit(0); } Fichier fichier= new Fichier(args[0]); if (!fichier.lirePossible()) { System.out.println(args[0] +" "+fichier.proprietes()); La classe FileReader est un flot (flux) pour la lecture des caractères. Permet d'accéder à des fichiers sur disque. Instancie et ouvre en lecture un flot à partir d'un objet File. Méthodes : read : lit un caractère sur le flot. close : ferme le flot. L'instruction de controle try...catch est obligatoire, car la méthode read peut lever (déclencher) une exception (erreur grave). Exécution: java LireFichier1 test3 Bonjour Tous Le Monde !!!
Ecrire des caractères dans un fichier import java.io.*; public class EcrireFichier1 { public static void main(String[] args) { if (args.length!=1) { System.out.println(" un seul argument SVP !"); System.exit(0); } Fichier fichier= new Fichier(args[0]); if (!fichier.ecrirePossible()) System.out.println(args[0] +" "+fichier.proprietes()); else { try { FileWriter flotEcriture = new FileWriter(fichier); for (char car='a'; car<='z'; ++car) flotEcriture.write (car); flotEcriture.close (); } catch (IOException e) { System.out.println(" erreur :" + e.toString()); } La classe FileWriter est un flot (flux) pour l'écriture des caractères. Permet d'accéder à des fichiers sur disque. Instancie et ouvre en écriture un flot à partir d'un objet File. Méthodes : write (char) écrit un caractère sur le flot. write (String) écrit le String. close ferme le flot. Exécution: java EcrireFichier1 test cat test abcdefghijklmnopqrstuvwxyz
Classe PrintWriter La classe PrintWriter permet d'écrire sur un flot de sortie des données en les représentant à l'aide de chaînes de caractères, à l'aide des méthodes print et println. import java.io.*; class Ecrire2{ public static void main(String[] argv) throws IOException { FileWriter fichier =new FileWriter ("test"); PrintWriter ecrivain= new PrintWriter (fichier); ecrivain.println ("bonjour, comment cela va-t-il ?"); ecrivain.println ("un peu difficile ?"); ecrivain.println ("On peut mettre des entiers : "+10); ecrivain.println ("Voici un caractère : "+'A'); ecrivain.close(); } }
Classe PrintWriter import java.io.*; class Ecrire2{ Exécution: public static void main(String[] argv) throws IOException { FileWriter fichier =new FileWriter ("test"); PrintWriter ecrivain= new PrintWriter (fichier); ecrivain.println ("bonjour, comment cela va-t-il ?"); ecrivain.println ("un peu difficile ?"); ecrivain.println ("On peut mettre des entiers : "+10); ecrivain.println ("Voici un caractère : "+'A'); ecrivain.close(); }} Exécution: java Ecrire2 cat test bonjour, comment cela va-t-il ? un peu difficile ? On peut mettre des entiers : 10 Voici un caractère : A FileWriter fichier =new FileWriter ("test",true); Exécution: java Ecrire2 cat test bonjour, comment cela va-t-il ? un peu difficile ? On peut mettre des entiers : 10 Voici un caractère : A
Classe PrintWriter import java.io.*; Exécution: class Ecrire2{ public static void main(String[] argv) throws IOException { FileWriter fichier =new FileWriter ("test",true); PrintWriter ecrivain= new PrintWriter (fichier); ecrivain.println ("bonjour, comment cela va-t-il ?"); ecrivain.println ("un peu difficile ?"); ecrivain.println ("On peut mettre des entiers : "+10); ecrivain.println ("Voici un caractère : "+'A'); ecrivain.close(); }} Exécution: javac Ecrire2.java java Ecrire2 cat test bonjour, comment cela va-t-il ? un peu difficile ? On peut mettre des entiers : 10 Voici un caractère : A
Rechercher un mot dans un fichier import java.io.*; import java.util.Scanner; class find{ public static void rechercher (String mot, File fichier){ String line = null; try { BufferedReader br = new BufferedReader(new FileReader(fichier)); int i = 1; //initialisation du numero de ligne while ((line = br.readLine()) != null) { if ( line.indexOf(mot) != -1) System.out.println("Mot trouve a la ligne " + i ); i++; } br.close(); } catch(IOException ioe) { System.out.println("Erreur IO" ); } } public static void main(String args[]) { System.out.println ("Veuillez saisir un mot :"); Scanner sc = new Scanner (System.in); String str = sc.nextLine(); rechercher (str, new File(args[0])); Exécution : $ java find find.java Veuillez saisir un mot : java Mot trouve a la ligne 1 Mot trouve a la ligne 2
Sérialisation
Sérialisation : enregistrer et restaurer des objets La sérialisation est un procédé introduit dans le JDK version 1.1 qui permet de rendre un objet persistant. Un objet est persistant si sa durée de vie est supérieure au programme qui l’a crée. Cet objet est mis sous une forme sous laquelle il pourra être reconstitué à l’identique. Ainsi il pourra être stocké sur un disque dur ou transmis au travers d’un réseau pour le créer dans une autre JVM. C’est le procédé qui est utilisé par exemple, par les sockets pour transmettre un objet via le réseau. Un objet sérialisable est transformable en une suite séquentiel d’octet et inversement, donc peut être stocké dans un fichier.
Serializable est une Interface sans méthode à implémenter. Objet Serializable import java.io.Serializable; class Compte implements Serializable { private String titulaire; private int numeroCompte; private double solde; Compte (String titulaire, int numeroCompte, double solde){ this.titulaire = titulaire; this.numeroCompte = numeroCompte; this.solde = solde; } public String toString (){ return "titulaire : "+ this.titulaire +"\t numeroCompte : "+this.numeroCompte +"\t solde : "+ this.solde; Serializable est une Interface sans méthode à implémenter.
Ecrire des objets dans un fichier import java.io.*; import java.util.*; public class EcrireBanque { public static void main(String[] args) { File fichier= new File("banque"); try { ObjectOutputStream flotEcriture =new ObjectOutputStream(new FileOutputStream(fichier)); ArrayList<Compte> liste=new ArrayList<Compte>(); liste.add(new Compte("aa",1,1000)); liste.add(new Compte("ab",2,2000)); liste.add(new Compte("ac",3,3000)); liste.add(new Compte("ad",4,4000)); flotEcriture.writeObject(liste); flotEcriture.close(); } catch (IOException e) {} }
Exécution java EcrireBanque cat banque (pour visualiser le contenu) í ♣sr ‼java.util.ArrayListx?Ò↔TÇa?♥ ☺I ♦sizexp ♦w♦ r ♠Compte→¥!7Þt┼à☻ ♥I ♀numeroCompteD ♣soldeL titulairet ↕Ljava/lang/String;xp ☺@?@ t ☻aasq ~ ☻ ☻@Y@ t ☻absq ~ ☻ ♥@§p t ☻acsq ~ ☻ ♦@¯@ t ☻adx
Classe ObjectOuputStream Cette classe permet de sérialiser un objet. On définit un fichier avec la classe FileOutputStream. On instancie un objet de classe ObjectOutputStream en lui fournissant en paramètre le fichier : ainsi, le résultat de la sérialisation sera envoyé dans le fichier. On appelle la méthode writeObject() en lui passant en paramètre l’objet à sérialiser. On appelle la méthode close() pour terminer l’opération. Lors de ces opérations une exception de type IOException peut être levée si un problème intervient avec le fichier. Après l’exécution de cet exemple, un fichier de sauvegarde est créé. On peut visualiser son contenu mais surtout pas le modifier car sinon il serait corrompu. En effet, les données contenues dans ce fichier ne sont pas toutes au format caractères.
Lire des objets dans un fichier import java.io.*; import java.util.*; public class LireBanque { public static void main(String[] args) { File fichier= new File("banque"); try { ObjectInputStream flotLecture = new ObjectInputStream(new FileInputStream(fichier)); Object lu = flotLecture.readObject(); ArrayList liste=(ArrayList)lu; for (int i=0; i<liste.size(); i++) { Object elem = liste.get(i); System.out.println(elem); } flotLecture.close(); } catch (Exception e) {}
Classe ObjectInputStream Cette classe permet de désérialiser un objet. On créer un objet de la classe FileInputStream qui représente le fichier contenant l’objet sérialisé. On créer un objet de type ObjectInputStream en lui passant le fichier en paramètre. Un appel à la méthode readObject() retourne l’objet avec un type Object. Un cast est nécessaire pour obtenir le type de l’objet. La méthode close() permet de terminer l’opération.
Exécution Exécution: java EcrireBanque cat banque (pour visualiser le contenu) í ♣sr ‼java.util.ArrayListx?Ò↔TÇa?♥ ☺I ♦sizexp ♦w♦ r ♠Compte→¥!7Þt┼à☻ ♥I ♀numeroCompteD ♣soldeL titulairet ↕Ljava/lang/String;xp ☺@?@ t ☻aasq ~ ☻ ☻@Y@ t ☻absq ~ ☻ ♥@§p t ☻acsq ~ ☻ ♦@¯@ t ☻adx Exécution : java LireBanque titulaire : aa numeroCompte : 1 solde : 1000.0 titulaire : ab numeroCompte : 2 solde : 2000.0 titulaire : ac numeroCompte : 3 solde : 3000.0 titulaire : ad numeroCompte : 4 solde : 4000.0