Java intensif Entrées/Sorties
Transcription
Java intensif Entrées/Sorties
Java intensif Entrées/Sorties Serge Rosmorduc 2013-2014 Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 1 / 50 Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 2 / 50 But du cours Donner les éléments de base pour comprendre les entrées/sorties en java. Cours 1 : Notions générales, lecture et écriture simple dans un fichier en java ; Cours 2 : Notions avancées, fichiers, lecture de textes structurés ; Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 3 / 50 Première partie I Notions fondamentales Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 4 / 50 Flux o n j o u r m o n d e \n ... ⇑ Définition : Un flux est une suite de données, finie ou infinie, dotée d’un curseur. Il existe deux grands types de flux : les flux en lecture (auquel cas le curseur correspond à une tête de lecture) et les flux en écriture. Les lectures (resp. écritures) dans le flux se font à la position du curseur. L’opération de lecture (resp. d’écriture) avance le curseur. Exemple de flux : canal de communication en réseau, fichier sur disque, entrée standard au clavier... ... b Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 5 / 50 Notion de fichier Définition : un fichier sera ici défini comme un flux enregistré sur un disque. Un fichier peut être envisagé de deux manières : comme objet du système de gestion de fichiers, il a une taille, des droits, une date de création, il appartient à un répertoire... par ailleurs, il contient un flux. En java, un fichier (existant ou non !) est représenté par un objet File (java 1.6) ou Path (à partir de 1.7). Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 6 / 50 Flux séquentiels et accès direct flux séquentiel : un flux séquentiel est un flux dans lequel les caractères sont lus (ou écrits) les uns après les autres, du premier au dernier. flux en accès direct : un flux en accès direct (Random Access) permet la lecture de n’importe quel caractère du flux. Le programmeur peut déplacer la tête de lecture (ou d’écriture) à n’importe quel endroit du flux. Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 7 / 50 Flux binaires et flux textes Définitions Flux binaire un flux binaire est une suite d’octets. L’interprétation de ces octets est à la charge du programme qui les lit ou les écrit. Flux texte un flux texte est une suite de caractères. Il est stocké selon un système de codage déterminé. Note : En dernier ressort, un flux texte est toujours contruit au dessus d’un flux binaire. Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 8 / 50 Flux binaire, exemples les fichiers créés par la plupart des bases de données ; la plupart des formats d’images ; les fichiers “.doc” de word les fichiers compressés (zip et autres) ... Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 9 / 50 Petit rappel d’architecture Plusieurs manière de coder un entier sur 4 octets en mémoire : numéro de l’octet valeur 0 3 1 100 2 30 3 20 big endian octet le plus significatif d’abord 56.892.948 = 3 ∗ 2563 + 100 ∗ 2562 + 30 ∗ 256 + 20 little endian octet le moins significatif d’abord 337.536.003 = 3 + 100 ∗ 256 + 30 ∗ 2562 + 20 ∗ 2563 java, 68000 : big endian x86 : little endian Voir classe ByteBuffer. Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 10 / 50 Exemple simpliste de fichier binaire : un format d’image couleur. Format du fichier : le fichier commence par deux entiers courts, codés en binaire sur deux octets, en mode “Big Endian” (Grandboutien) ; ces entiers sont respectivement la largeur et la hauteur de l’image. il comporte ensuite la liste des points de l’image, ligne après ligne, avec trois octets par points, représentant les valeurs R, V, et B de la couleur. Pseudo code pour écrire un petit fichier dans ce format : écrire(0); écrire(3); // largeur 3 pixels écrire(0); écrire(1); // hauteur 1 pixel écrire(255); écrire(0); écrire(0); // 1 pixel rouge écrire(100); écrire(100); écrire(0); // 1 pixel jaune écrire(255); écrire(255); écrire(255); // 1 pixel blanc Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 11 / 50 Fichiers textes et codage des caractères Approche simple (anciennement) : un fichier est une suite de nombre entre 0 et 255 ; le codage d’un fichier texte associe à chaque nombre un caractère ; le codage dépend généralement du système et de sa configuration. Exemple caractère espace 0 (zéro) 1 (un) a A é œ code ASCII 32 48 49 97 65 (non) (non) Serge Rosmorduc () code latin-1 32 48 49 97 65 233 (non) code MacRoman 32 48 49 97 65 142 207 Java intensifEntrées/Sorties 2013-2014 12 / 50 Unicode Un codage pour tous les caractères → dépasse l’octet ! Les codes vont de 0 à 0x10FFFF (1.114.111) comment les représenter concrètement : UTF-8, UTF-16 (BE/LE), UTF-32(BE/LE) I I texte Latin-1 UTF-8 pour les fichiers : UTF-8 (plus compact, pas d’ambiguı̈té BE/LE) ; en interne, un char java est en UTF-16. u 0x75 0x75 Serge Rosmorduc () n 0x6E 0x6E 0x20 0x20 é 0xE9 0xC3 0xA9 Java intensifEntrées/Sorties t 0x74 0x74 é 0xE9 0xC3 0xA9 2013-2014 13 / 50 Fins de lignes trois codages différents unix : saut de ligne, ’\n’, code 10 mac : retour chariot, ’\r’, code 13 dos/windows : ’\r\n’ Attention : un fichier créé par windows et lu sous unix comportera probablement le saut de lignes windows ! Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 14 / 50 Deuxième partie II Et en Java ? Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 15 / 50 Exemple d’écriture public static void testEcritureTexte (String fname) throws IOException { // On crée un objet Writer, ce qui ouvre le fichier FileWriter f= new FileWriter(fname); try { // On utilise cet objet pour écrire f.write("hello "); f.write("world."); f.write("It works !"); } finally { // On ferme le flux f.close(); } } Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 16 / 50 Écriture, points importants La création du FileWriter permet crée le fichier et permet d’écrire dedans ; on écrit avec write() ; ne jamais oublier de fermer les fichiers ouverts. pratiquement toutes les méthodes d’I/O renvoient des IOExceptions. Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 17 / 50 Exemple de lecture public static void testLectureTexte (String fname) throws IOException { FileReader f= new FileReader(fname); try { // Le résultat de read doit être un entier // (à cause du -1 qui est renvoyé en fin de fichier) int cc; cc= f.read(); while (cc != -1) { // Pour ranger cc dans un char, il faut un cast : char c= (char)cc; ... on fait quelque chose de la valeur de c... cc= f.read(); // Lecture du suivant. } } finally { f.close(); } } Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 18 / 50 Lecture, points importants FileReader f= new FileReader(fname) : on crée le lecteur. la méthode read() renvoie le code du caractère lu ou -1 si on arrive à la fin du fichier. -1 n’est pas un code de caractère. On ne peut pas le ranger dans un char. C’est pour ça que cc est un int. chaque appel de read() avance dans le fichier. D’où l’intérêt de stocker la valeur reçue dans une variable. que se passe-t-il si on oublie le read() dans la boucle ? Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 19 / 50 Récapitulation On manipule le flux à travers un objet (Reader, Writer, OutputStream ou InputStream) ; la création de l’objet ouvre le flux (et crée le fichier si on est en écriture) ; ouvrir un fichier existant en écriture efface l’ancien fichier ; on doit toujours fermer les flux ouverts ; écriture : on ouvre, on écrit, on ferme ; lecture : on ouvre, on boucle en lisant, on atteint la fin du fichier, on ferme ; read() et write() avancent dans le fichier ; la lecture est plus complexe que l’écriture Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 20 / 50 Architecture des entrées/sorties en Java Flux séquentiels Important ! ! ! Lecture Binaire InputStream Texte Reader Écriture OutputStream Writer Flux à accès direct RandomAccessFile. Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 21 / 50 Organisation des classes remarquez les méthodes abstraites ! Writer close() flush() write(cbuf : char[]) write(cbuf : char[],off : int,len : int) write(c : int) write(s : String) write(s : String,off : int,len : int) BufferedWriter newLine() Un BufferedWriter écrit dans un autre Writer Serge Rosmorduc () OutputStreamWriter out : OutputStream StringWriter toString() : String PrintWriter print(s : String) FileWriter Java intensifEntrées/Sorties 2013-2014 22 / 50 Nommage des classes Typiquement : ∅ Buffered StringBuffer/ByteArray File Filter Piped InputStream OutputStream Reader Writer D’autres classes sont plus spécifiques : e.g. PrintWriter. Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 23 / 50 Filtrage Certaines classes fonctionnent comme des filtres ; LineNumberReader f= new LineNumberReader( new InputStreamReader(System.in)); ... c= f.read(); On lit l’entrée standard (System.in) (binaire) ; Le InputStreamReader : flux texte au dessus de cette entrée LineNumberReader : reader qui compte les lignes. Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 24 / 50 La classe Writer, étude détaillée void write (int c) throws IOException Écrit le caractère dont le code est c. Notez que cette méthode fonctionne correctement que c soit un char ou un int. void write (char [] s) throws IOException écrit le contenu de s. void write (char[] s, int off, int longueur) throws IOException écrit les caractères de s compris entre l’indice off et off + longueur. Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 25 / 50 void write (String s) throws IOException écrit la chaı̂ne s. void flush () throws IOException Réalise effectivement la copie sur le support. C’est utile dans le cas de classes comme BufferedWriter, où les données sont stockées temporairement en mémoire. void close () throws IOException ferme le Writer Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 26 / 50 La classe Reader : étude détaillée int read () throws IOException lit un caractère sur l’entrée, et renvoie son code, ou -1 si la fin du fichier est atteinte. int read (char [] buf) throws IOException Remplit le tableau buf avec les caractères lus. Attention, cette méthode n’alloue pas le tableau. La méthode renvoie le nombre de caractères lus, ou -1 si la fin du fichier est atteinte. Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 27 / 50 int read (char [] buf, int dep, int longueur) throws IOException Copie les caractères lus dans buf, en commençant à l’indice dep, en en lisant au maximum longueur caractères. La méthode renvoie le nombre de caractères lus, ou -1 si la fin du fichier est atteinte. void close () throws IOException ferme le lecteur. Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 28 / 50 Reader et Writer, précisions sur les sauts de ligne Codage des sauts de ligne dépend du système d’exploitation ; Reader et Writer ne distinguent pas les sauts de lignes des autres caractères ; ils manipulent donc \n et \r comme des caractères comme les autres. pour lire ligne par ligne, le plus simple est d’utiliser un BufferedReader. Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 29 / 50 Classes InputStream et OutputStream En gros, même méthodes que respectivement Reader et Writer ; Mais écrivent et lisent des octets ; les méthodes recoivent ou renvoient des int entre 0 et 255 ; Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 30 / 50 Lecture d’un fichier Classes FileOutputStream, FileWriter Ouverture/création du flux : FileOutputStream (File file) throws IOException FileOutputStream (String name) throws IOException FileOutputStream (String name, boolean append) throws FileNotFoundException ouvre le flux en écriture ; ajoute les données écrites à la fin du fichier actuel si append vaut vrai. Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 31 / 50 Lecture d’un fichier Classes FileReader, FileInputStream FileInputStream (File file) throws FileNotFoundException FileInputStream (String name) throws FileNotFoundException Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 32 / 50 Déclaration de Reader Qu’est-ce qui est mieux : 1 void maFonction(FileReader f) 2 void maFonction(Reader r) Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 33 / 50 Déclaration de Reader Qu’est-ce qui est mieux : 1 void maFonction(FileReader f) 2 void maFonction(Reader r) Réponse : avec Reader, la fonction sera utilisable pour tous les Reader. On préfère donc cette version dans la plupart des cas. De même pour les variables d’instance de type Reader. On peut écrire : Reader r= new FileReader("toto.txt"); (l’intérêt est plus mitigé). Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 33 / 50 Classes orientées chaı̂nes : écriture CharArrayWriter, ByteArrayOutputStream, StringWriter int c; FileReader f= new FileReader(args[0]); StringWriter sw= new StringWriter(); c= f.read(); while (c != -1) { // écrit c dans sw sw.write(c); c= f.read(); } // Copie le contenu de sw dans s. String s= sw.toString(); System.out.println(s); Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 34 / 50 Classes orientées chaı̂nes : lecture CharArrayReader, ByteArrayInputStream, StringReader, StringBufferInputStream Reader f= new StringReader("hello tout le monde"); int c; while ((c= f.read()) != -1) { System.out.println((char) c); } f.close(); utiliser des méthodes prévues pour des flux sur des chaı̂nes de caractères. tests JUnit : pas besoin de créer de fichier, on teste sur des StringReader ou des StringWriter... Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 35 / 50 Ponts entre flux binaires et textes Les classes InputStreamReader et OutputStreamWriter permettent de construire un flux orienté caractères au dessus d’un flux d’octets. Elles permettent de spécifier le codage d’un fichier (impossible avec FileWriter/FileReader Ouverture explicite en UTF-8 Reader r= new InputStreamReader( new FileInputStream("toto.txt"), "UTF-8"); Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 36 / 50 BufferedReader Lecture Bufferisée Souvent utilisée à cause de sa méthode readLine() Utilise un tampon (buffer). Lecture plus rapide ; retour en arrière : void reset () throws IOException revient à la dernière marque void mark (int limite) throws IOException pose une marque (oubliée après limite caractères) lecture ligne à ligne : String readLine () throws IOException renvoie le texte de la ligne (sans la fin de ligne), ou null si le fichier est terminé. Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 37 / 50 1 2 3 4 5 6 7 1 2 3 4 5 6 Lecture d’un fichier ligne à ligne avec BufferedReader code propre : BufferedReader r = . . . . ; S t r i n g s= r . r e a d L i n e ( ) ; while ( s ! = n u l l ) { ... s= r . r e a d L i n e ( ) ; } r . close ( ) ; En réalité : BufferedReader r = . . . . ; String s ; while ( ( s= r . r e a d L i n e ( ) ) ! = n u l l ) { ... } r . close ( ) ; (p.s. normalement, le close est dans un finally) . Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 38 / 50 Troisième partie III Algorithmes Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 39 / 50 Approche des algorithmes de lecture Exemple : lecture et interprétation à la main d’une suite de nombres réels représentés en texte. On commence par spécifier précisément la forme du texte (qu’est ce qui est optionnel, qu’est-ce qui ne l’est pas...) ici : I I I exemple lecture d’une heure, de la forme : un ou deux chiffres, zéro ou plusieurs espaces, la lettre h , zéro ou plusieurs espaces, un ou deux chiffres. expression régulière : [0-9][0-9]? * h * [0-9][0-9]? on lit un caractère, puis on l’interprète → on termine une interprétation en lisant le caractère suivant ; On raisonne en terme d’états. À moment donné, où en sommes-nous, quels caractères pouvons nous attendre ? lié à la notion d’automates Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 40 / 50 Début : lecture d’un ou deux chiffres pour l’heure // On lit le premier caractère avant de commencer c= lire() si c n’est pas un chiffre erreur() fin si h= valeur de c c= lire() //on avance... //lecture du chiffre "optionnel" si c est un chiffre h= h * 10 + valeur de c c= lire() // on avance fin si à la fin, c correspond au caractère qui suit le texte reconnu intérêt de -1 comme fin de flux ; on est prêt à lire la suite... Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 41 / 50 Lecture de zéro ou n espaces, // c a déjà été lu... tant que c = espace c= lire() fin tant que on est sûr que c n’est pas un espace après la boucle ; on s’arrête forcément : fin du fichier, lire() renvoie -1. Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 42 / 50 Lecture de h Normalement, après les espaces, le caractère qui suit est un h . si ça n’est pas le cas, on a une erreur ; si c’est le cas, on passe le h et on avance au caractère suivant. si c != ’h’ alors erreur() fin si c= lire() Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 43 / 50 On réunit le tout... c= si h= c= si lire() c n’est pas un chiffre alors erreur() fin valeur de c lire() c est un chiffre h= h * 10 + valeur de c c= lire() fin si tant que c = espace faire c= lire() fin tant si c != ’h’ alors erreur() fin si c= lire() tant que c = espace faire c= lire() fin tant si c n’est pas un chiffre alors erreur() fin m= valeur de c c= lire() si c est un chiffre m= m * 10 + valeur de c c= lire() fin si Serge Rosmorduc () Java intensifEntrées/Sorties si que que si 2013-2014 44 / 50 Exemple plus complexe : lecture de nombres réels (en réalité, c’est bien entendu déjà fait ailleurs dans les classes java) un nombre est de la forme ’-’ ? [0-9]+ (’.’ [0-9]+) ? ils sont séparés par une suite de 0 espaces ou plus. Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 45 / 50 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 Algorithme pour ’-’ ? [0-9]+ (’.’ [0-9]+) ? : l u = read ( ) nb= 0 NEGATIF= FAUX SI l u == ’− ’ ALORS n e g a t i f = VRAI l u = read ( ) / / s a u t e r l e ’ − ’ ! FIN SI SI l u non c h i f f r e e x c e p t i o n FIN SI REPETER nb= nb ∗ 10 + ( l u − ’ 0 ’ ) l u = read ( ) TANT QUE l u e s t un c h i f f r e SI l u == ’ . ’ ALORS l u = read ( ) dec= 0 . 1 SI l u non c h i f f r e e x c e p t i o n FIN SI REPETER nb= nb + dec ∗ ( l u − ’ 0 ’ ) dec= dec ∗0.1 l u = read ( ) TANT QUE l u e s t un c h i f f r e FIN SI Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 46 / 50 Quatrième partie IV Java 7 (et un peu 6 aussi) pleins de nouveautés... Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 47 / 50 Bloc try with resource garantit la fermeture d’un ou plusieurs flux, même en cas d’exception. Forme try (CREATION DE RESOURCES R1, R2...) { CODE UTILISANT R1, R2... } Les resources sont des objets de classes qui ont une méthode close. (Closeable) public static void testEcritureTexte (String fname) throws IOException { try (FileWriter f= new FileWriter(fname)) { f.write("hello "); f.write("world."); f.write("It works !"); } // pas besoin de close : //f est fermé automatiquement. } Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 48 / 50 Classe Files Classe utilitaire (helper class) = classe pour méthodes statique. Utilise Path et non plus File (cours prochain) méthodes de manipulation de fichier (copie, déplacement...) ; comprend des notions complexes (liens symboliques, etc.) ; contient des méthodes-fabriques (factory methods) pour créer des flux. Exemple : static BufferedReader newBufferedReader (Path path, Charset cs) throws throws IOException Crée un flux texte en lecture, en spécifiant le chemin du fichier et son codage. (Rmq : pour le codage, utiliser la méthode statique Charset.forName()) Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 49 / 50 Entrées/sorties textes simplifiées classe java.io.Console, récupérable par l’appel System.console(). Entrées/sorties clavier/écran formatées, lecture de mot de passe, etc ; Scanner (on en cause au cours suivant) ; PrintWriter : affichages de type printf du C (déjà en 1.5). Serge Rosmorduc () Java intensifEntrées/Sorties 2013-2014 50 / 50