1 / 41

10 ième Classe (Mardi, 11 novembre) CSI2572

10 ième Classe (Mardi, 11 novembre) CSI2572. Flots d’entrées-sorties en C++.

shalom
Download Presentation

10 ième Classe (Mardi, 11 novembre) CSI2572

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 10ième Classe (Mardi, 11 novembre)CSI2572

  2. Flots d’entrées-sorties en C++ • Les entrées-sorties, c’est-à-dire les opérations de lecture à partir du clavier, d’un fichier disque ou d’un périphérique, et les écritures à l’écran, sur disque, imprimante ou périphérique, sont parmi les opérations les plus fréquentes sur ordinateur. • En C++, on dispose de « flots » d’entrée ou de sortie qui permettent (supposément) facilement ces opérations. • Comme pour le langage C, les instructions entrées/sorties ne font pas partie des instructions du langage. Elles sont dans une librairie standardisée qui implémente les flots à partir de classes.

  3. Flots d’entrées-sorties en C++ • Un flux (ou stream) est une abstraction logicielle représentant un flot de données entre : • une source produisant de l'information • une cible consommant cette information. • Un flux peut être représenté comme un buffer associé à des mécanismes de gestions prennent en charge, quand le flux est créé, l'acheminement de ces données.

  4. Flots d’entrées-sorties en C++ • Par défaut, chaque programme C++ peut utiliser 3 flots : • cout qui correspond à la sortie standard • cin qui correspond à l'entrée standard • cerr qui correspond à la sortie standard d'erreur • Pour utiliser d'autres flots, vous devez donc créer et attacher ces flots à des fichiers (fichiers normaux ou fichiers spéciaux) ou à des tableaux de caractères.

  5. Flots d’entrées-sorties en C++ • Les classes de flots sont déclarées dans iostream.h et permettant la manipulation des périphériques standards • ios : classe de base des entrées/sorties par flot. Elle contient un objet de la classe streambuf pour la gestion des tampons d'entrées/sorties. • istream : classe dérivée de ios pour les flots en entrée. • ostream : classe dérivée de ios pour les flots en sortie. • iostream : classe dérivée de istream et de ostream pour les flots bidirectionnels.

  6. Flots d’entrées-sorties en C++

  7. Flots d’entrées-sorties en C++ • istream_withassign, ostream_withassign et iostream_withassign sont des classes dérivées respectivement de istream, ostream et iostream et qui ajoute l'opérateur d'affectation. • Les flots standards cin, cout et cerr sont des instances de ces classes.

  8. La classe ios • La classe ios est la base des flux. Il ne s’agit pas d’une classe abstraite, mais peu s’en faut. Elle ne permet qu’un petit nombre d’opérations, et n’a pas en principe à être utilisée telle quelle. • Cependant elle fournit un certain nombre de constantes énumérées pour la gestion des flots, avec les petites fonctions membres en ligne afférentes. • Une instance de ios est normalement toujours rattachée à un tampon streambuf. La fonction membre streambuf* rdbuf() renvoie un pointeur sur ce tampon.

  9. La classe ios • Une première énumération dans ios contient une liste de masques unitaires • Ce sont des entiers dont un seul bit vaut 1. • Ils sont utilisés sur un champ particulier et indiquent l’état du flot. • Ce champ d’état n’est pas accessible directement mais peut être lu par la fonction membre int rdstate(void). Voici les bits indicateurs qui peuvent être positionnés :

  10. La classe ios • ios::goodbit Lorsque ce bit vaut 0, ainsi que tous les autres, tout va bien. La fonction membre int good(void) renvoie 1 si tous les bits d’état sont à zéro (tout va bien), 0 sinon. • ios::eofbit Lorsque ce bit vaut 1, la fin du fichier est atteinte. La fonction membre int eof() renvoie 1 dans ce cas, 0 sinon. • ios::failbit Ce bit est à 1 lorsqu’une opération a échoué. Le flot peut être réutilisé. • ios::badbit Ce bit est à 1 lorsqu’une opération invalide a été tentée ; en principe le flot peut continuer à être utilisé mais ce n’est pas certain. • ios::hardfail Ce bit est à 1 lorsqu’une erreur grave s’est produite ; il ne faut plus utiliser le flot.

  11. La classe ios • La fonction membre int bad(void) renvoie 1 si l’un des deux bits ios::badbit ou ios::hardfail est à 1, 0 sinon. • La fonction membre int fail(void) renvoie 1 si l’un des trois bits ios::badbit ou ios::failbit ou ios::hardfail est à 1, et 0 sinon. • La fonction membre void clear(int i = 0) permet de modifier l’état du flot. Par exemple, l’écriture fl.clear(ios::failbit) positionne le bit ios::failbit du flot fl, indiquant une erreur grave.

  12. La classe ios • Il y a aussi deux opérateurs utils: class ios { public: // ... operator void* (); int operator! (); }; • L’opérateur ! (redéfini pour cette classe) renvoie 1 si l’un des bits d’état est à 1 (flot incorrect), 0 sinon. Au contraire l’opérateur void*, lui aussi redéfini, renvoie 0 si l’un des bits d’état est à 1, un pointeur non nul (et dépourvu de signification) sinon. Cela permet des écritures du type : iostream fl; // ... if (fl) cout << "Tout va bien !\n"; // ... if (!fl) cout << "Une erreur s'est produite.\n";

  13. La classe ios • Une autre énumération regroupe les masques unitaires utilisés pour le champ de mode. Celui-ci indique de quelle façon les données sont lues ou écrites, et ce qui se passe au moment de l’ouverture du flot. On l’utilise surtout pour les fichiers. Voici la liste de ces bits : • ios::in Fichier ouvert en lecture. • ios::out Fichier ouvert en écriture. • ios::app Ajoute les données, en écrivant toujours à la fin (et non à la position courante). • ios::ate Aller à la fin du fichier à l’ouverture (au lieu de rester au début).

  14. La classe ios • ios::trunc Supprime le contenu du fichier, s’il existe déjà ; cette suppression est automatique pour les fichiers ouverts en écriture, sauf si ios::ate ou ios::app a été précisé dans le mode. • ios::nocreate Pour une ouverture en écriture, ne crée pas le fichier s’il n’existe pas déjà ; une erreur (bit ios::failbit positionné) est produite dans le cas où le fichier n’existe pas encore. • ios::noreplace Pour une ouverture en écriture, si ni ios::ate ni ios::app ne sont positionnés, le fichier n’est pas ouvert s’il existe déjà, et une erreur est produite. • ios::binary Fichier binaire, ne faire aucun formatage. Par exemple l’écriture suivante : fstream fl("EXEMP.CPP", ios::in|ios::out|ios::app); ouvre le fichier EXEMP.CPP en lecture et écriture, avec ajout des nouvelles données à la fin

  15. La classe streambuf • Un tampon, également appelé cache, est une zone mémoire dans laquelle les opérations d'écriture et de lecture se font et dont le contenu est mis en correspondance avec les données d'un média physique sous-jacent. Les mécanismes de cache ont essentiellement pour but d'optimiser les performances des opérations d'entrée / sortie. • La classe streambuf est la classe de gestion des tampons d’entrées-sorties. • Chaque flot va contenir un pointeur sur un tampon (ou plusieurs éventuellement)

  16. La classe ostream • La classe ostream est la classe fondamentale des flots de sortie. Elle dérive de ios de manière publique et virtuelle class ostream : public virtual ios { ... • On y trouve un constructeur: ostream::ostream(streambuf*) qui associe le tampon au flot et un destructeur virtuel, comme dans ios. Comme dans ios encore, l’opérateur d’affectation et le constructeur de copie n’y sont pas utilisables, car ils ne sont pas redéfinis (et comme ils ne sont pas accessibles dans ios, on ne peut utiliser ceux par défaut).

  17. La classe ostream • L’opérateur << est redéfini pour les flots de sortie sous la forme d’une méthode: ostream& operator<<(type) pour tous les types prédéfinis (y compris unsigned char* et signed char* pour les chaînes de caractères), ainsi que void* (pour écrire la valeur d’un pointeur) et même streambuf* (pour prendre les caractères d’un autre tampon et les écrire). • Nous avons déjà utilisé bien des fois cet opérateur avec cout.

  18. La classe ostream cout << i << " ce jour " << d << '\n'; équivaut à : cout.operator<< (i).operator<< ("ce jour").operator<< (d).operator<<('\n'); et donc à l’appel de quatre fonctions différentes.

  19. Lorsqu’on écrit une nouvelle classe d’objets, on peut donc définir un opérateur << adapté: class fraction { int num, den; public : // ... friend ostream& operator<<(ostream& os, fraction f){ return os << f.num << '/' << f.den; } };

  20. La classe ostream En plus de l'opérateur d'injection (<<), la classe ostream contient les principales méthodes suivantes : • ostream & put(char c); qui insère un caractère dans le flot. Exemple : cout.put('\n'); • ostream & write(const char *, int n); insère n caractères dans le flot Exemple : cout.write("Bonjour", 7);

  21. La classe ostream • Un flot de sortie pointant sur un fichier ou une organisation du même genre possède un indicateur de position. Cet indicateur marque l’emplacement de la prochaine lecture ; il avance à chaque écriture du nombre de caractères écrits. • On peut connaître la valeur de cet indicateur de position par la fonction membre streampos tellp(void) ; • Le type streampos est identique à long.

  22. La classe ostream • Il y a deux moyens de modifier cet indicateur, autrement qu’en faisant des écritures. Le premier consiste à appeler la méthode ostream& seekp(streampos n) avec la nouvelle valeur souhaitée. L'indicateur de position se place à n octet(s) par rapport au début du flux. Les positions dans un flot commencent à 0 et le type streampos correspond à la position d'un caractère dans le fichier.

  23. La classe ostream • Le second consiste à donner un déplacement par rapport à une position de référence (type streamoff, qui est aussi égal à long). On utilise pour cela ostream& seekp(streamoff dep, seek_dir dir) se positionne à dep octet(s) par rapport : • au début du flot : dir = beg • à la position courante : dir = cur • à la fin du flot : dir = end (et dep est négatif!)

  24. streampos old_pos = fout.tellp(); // mémorise la position fout.seekp(0, end); // se positionne à la fin du flux cout << "Taille du fichier : " << fout.tellp() << " octet(s)\n"; fout.seekp(old_pos, beg); // se repositionne comme au départ

  25. La classe ostream • Les flots de sortie sont retardés, c’est-à-dire que les données prennent place dans le tampon jusqu’à ce qu’il soit plein ou jusqu’à la fermeture du flot. • Pour forcer le tampon à écrire ces données tout de suite, il suffit d’appeler la méthode: ostream& flush(void) (la valeur renvoyée est le flot lui-même).

  26. La classe istream • La classe istream, utilisée pour les flots d’entrée, dérive elle aussi de manière virtuelle et publique de ios ; comme ostream, elle ne possède qu’un constructeur: istream:: istream(streambuf*) • Fournit des entrées formatées et non formatées (dans un streambuf) • Surdéfinit de l'opérateur >>

  27. La classe istream En plus de l'opérateur d'extraction (>>), la classe istream contient les principales méthodes suivantes : • lecture d'un caractère : • int get(); retourne la valeur du caractère lu (ou EOF si la fin du fichier est atteinte) • istream & get(char &c); extrait le premier caractère du flux (même si c'est un espace) et le place dans c. • int peek(); lecture non destructrice du caractère suivant dans le flux. Retourne le code du caractère ou EOF si la fin du fichier est atteinte.

  28. La classe istream • Lecture d'une chaîne de caractères : • istream & get(char *ch, int n, char delim='\n'); extrait n -1 caractères du flux et les place à l'adresse ch. La lecture s'arrête au délimiteur qui est par défaut le '\n' ou la fin de fichier. Le délimiteur ('\n' par défaut) n'est pas extrait du flux. • istream & getline(char *ch, int n, char delim='\n'); comme la méthode précédente sauf que le délimiteur est extrait du flux mais n'est pas recopié dans le tampon.

  29. La classe istream • istream & read(char *ch, int n); extrait un bloc d' au plus n octets du flux et les place à l'adresse ch. Le nombre d'octets effectivement lus peut être obtenu par la méthode gcount(). • int gcount(); retourne le nombre de caractères non formatés extraits lors de la dernière lecture • streampos tellg(); retourne la position courante dans le flot

  30. La classe istream • istream & seekg(streampos n); se positionne à n octet(s) par rapport au début du flux. Les positions dans un flot commencent à 0 et le type streampos correspond à la position d'un caractère dans le fichier. • istream & seekg(streamoff dep, seek_dir dir); se positionne à dep octet(s) par rapport : • au début du flot : dir = beg • à la position courante : dir = cur • à la fin du flot : dir = end (et dep est négatif!) • istream & flush(); vide les tampons du flux

  31. La classe iostream • La classe iostream est utilisée lorsqu’on souhaite faire à la fois des lectures et des écritures. Elle hérite de ostream et istream: class iostream : public istream, public ostream { public: iostream(streambuf*); virtual ~iostream(); protected: iostream(); }; • Il n’est pas possible de déclarer une instance sans l’initialiser avec un tampon streambuf*, sauf pour les classes descendantes • Les deux opérateurs >> et << restent bien entendu disponibles, ainsi que tous les autres membres.

  32. Fichiers (ouverture, lecture, fermeture) • Les classes permettant la manipulation des fichiers disques sont déclarées dans fstream.h

  33. Fichiers (ouverture, lecture, fermeture) • fstreambase : classe de base pour les classes dérivées ifstream, ofstream et fstream. Elle même est dérivée de ios et contient un objet de la classe filebuf (dérivée de streambuf). • ifstream : classe permettant d'effectuer des entrées à partir des fichiers. • ofstream : classe permettant d'effectuer des sorties sur des fichiers. • fstream : classe permettant d'effectuer des entrées/sorties à partir des fichiers.

  34. Fichiers • Comme pour les flux d'entrée / sortie sur les chaînes de caractères, il est possible d'initialiser le flux dès sa construction ou a posteriori. • Les méthodes importantes sont la méthode open, qui permet d'ouvrir un fichier, la méthode is_open, qui permet de savoir si le flux contient déjà un fichier ouvert ou non, et la méthode close, qui permet de fermer le fichier ouvert.

  35. int main(void) { // Ouvre le fichier de données : fstream f("fichier.txt", ios_base::in | ios_base::out | ios_base::trunc); if (f.is_open()) { // Écrit les données : f << 2 << " " << 45.32 << " " << 6.37 << endl; // Replace le pointeur de fichier au début : f.seekg(0); // Lit les données : int i; double d, e; f >> i >> d >> e; cout << "Les données lues sont : " << i << " " << d << " " << e << endl; // Ferme le fichier : f.close(); } return 0; }

  36. Ouverture du fichier et association avec un flux : • C'est la méthode open() qui permet d'ouvrir un fichier et d'associer un flux avec ce dernier. void open(const char *name, int mode, int prot=filebuf::openprot); name : nom du fichier à ouvrir mode : mode d'ouverture du fichier

  37. Ouverture du fichier et association avec un flux : enum open_mode de la classe ios : enum open_mode { app, // ajout des données en fin de fichier. ate, // positionnement à la fin du fichier. in, // ouverture en lecture //(par défaut pour ifstream). out, // ouverture en écriture //(par défaut pour ofstream).

  38. Ouverture du fichier et association avec un flux : binary, // ouverture en mode binaire //(par défaut en mode texte). trunc, // détruit le fichier s'il existe et le recrée //(par défaut si out est spécifié sans que ate //ou app ne soit activé). nocreate, // si le fichier n'existe pas, l'ouverture // échoue. noreplace // si le fichier existe, l'ouverture échoue, // sauf si ate ou app sont activés. };

  39. #include <fstream.h> ifstream f1; f1.open("essai1.tmp"); // ouverture en lecture du fichier ofstream f2; f2.open("essai2.tmp"); // ouverture en écriture du fichier fstream f3; f3.open("essai3.tmp", ios::in | ios::out); // ouverture en lecture/écriture

  40. On peut aussi appeler les constructeurs des différentes classes et combiner les 2 opérations de définition du flot et d'ouverture. #include <fstream.h> ifstream f1("essai1.tmp"); // ouverture en lecture du fichier ofstream f2("essai2.tmp"); // ouverture en écriture du fichier fstream f3("essai3.tmp", ios::in | ios::out);// ouverture en lecture/écriture

  41. Note : Il est important de bien noter que le destructeur des flux ne ferme pas les fichiers. En effet, ce sont les tampons utilisés de manière sous-jacente par les flux qui réalisent les opérations sur les fichiers. Il est même tout à fait possible d'accéder à un même fichier avec plusieurs classes de flux, bien que cela ne soit pas franchement recommandé. Vous devrez donc prendre en charge vous-même les opérations d'ouverture et de fermeture des fichiers.

More Related