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

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

  • Upload
    shalom

  • View
    21

  • Download
    0

Embed Size (px)

DESCRIPTION

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

Citation preview

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

1010ièmeième Classe (Mardi, 11 novembre) Classe (Mardi, 11 novembre)CSI2572CSI2572

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

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.

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

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

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.

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

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

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.

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

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

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.

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

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

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

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

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.

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

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

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.

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

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 :

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

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.

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

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.

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

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";

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

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).

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

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

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

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)

La classe streambuf

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

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).

La classe ostream

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

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.

La classe ostream

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

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.

La classe ostream

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

class fraction {

int num, den;

public :

// ...

friend

ostream& operator<<(ostream& os, fraction f){

return os << f.num << '/' << f.den;

}

};

Lorsqu’on écrit une nouvelle classe d’objets, on peut donc définir un opérateur << adapté:

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

En plus de l'opérateur d'injection (<<), la classe ostreamcontient 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);

La classe ostream

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

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.

La classe ostream

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

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.

La classe ostream

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

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!)

La classe ostream

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

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

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

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).

La classe ostream

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

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 >>

La classe istream

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

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.

La classe istream

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

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.

La classe istream

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

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 extraitslors de la dernière lecture

streampos tellg();

retourne la position courante dans le flot

La classe istream

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

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

La classe istream

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

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.

La classe iostream

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

Les classes permettant la manipulation des fichiers disques sont déclarées dans fstream.h

Fichiers (ouverture, lecture, fermeture)

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

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.

Fichiers (ouverture, lecture, fermeture)

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

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.

Fichiers

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

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; }

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

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

Ouverture du fichier et association avec un flux :

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

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).

Ouverture du fichier et association avec un flux :

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

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.

};

Ouverture du fichier et association avec un flux :

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

#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

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

#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

On peut aussi appeler les constructeurs des différentes classes et combiner les 2 opérations de définition du flot et d'ouverture.

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

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.