Title: 10i
110ième Classe (Mardi, 11 novembre)CSI2572
2Flots dentrées-sorties en C
- Les entrées-sorties, cest-à-dire les opérations
de lecture à partir du clavier, dun fichier
disque ou dun 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 dentré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. -
3Flots dentré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.
4Flots dentré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. -
5Flots dentré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.
6Flots dentrées-sorties en C
7Flots dentré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.
8La classe ios
- La classe ios est la base des flux. Il ne sagit
pas dune classe abstraite, mais peu sen faut.
Elle ne permet quun petit nombre dopérations,
et na 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.
9La 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 nest pas accessible directement
mais peut être lu par la fonction membre int
rdstate(void). Voici les bits indicateurs qui
peuvent être positionnés
10La classe ios
- iosgoodbit 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. - ioseofbit Lorsque ce bit vaut 1, la fin du
fichier est atteinte. La fonction membre int
eof() renvoie 1 dans ce cas, 0 sinon. - iosfailbit Ce bit est à 1 lorsquune opération
a échoué. Le flot peut être réutilisé. - iosbadbit Ce bit est à 1 lorsquune opération
invalide a été tentée en principe le flot peut
continuer à être utilisé mais ce nest pas
certain. - ioshardfail Ce bit est à 1 lorsquune erreur
grave sest produite il ne faut plus utiliser
le flot.
11La classe ios
- La fonction membre int bad(void) renvoie 1 si
lun des deux bits iosbadbit ou ioshardfail
est à 1, 0 sinon. - La fonction membre int fail(void) renvoie 1 si
lun des trois bits iosbadbit ou iosfailbit
ou ioshardfail 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(iosfailbit) positionne le
bit iosfailbit du flot fl, indiquant une erreur
grave.
12La classe ios
- Il y a aussi deux opérateurs utils
- class ios
- public
- // ...
- operator void ()
- int operator! ()
-
- Lopérateur ! (redéfini pour cette classe)
renvoie 1 si lun des bits détat est à 1 (flot
incorrect), 0 sinon. Au contraire lopérateur
void, lui aussi redéfini, renvoie 0 si lun 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 ltlt "Tout va
bien !\n" // ... if (!fl) cout ltlt "Une erreur
s'est produite.\n"
13La 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
louverture du flot. On lutilise surtout pour
les fichiers. Voici la liste de ces bits - iosin Fichier ouvert en lecture.
- iosout Fichier ouvert en écriture.
- iosapp Ajoute les données, en écrivant
toujours à la fin (et non à la position
courante). - iosate Aller à la fin du fichier à louverture
(au lieu de rester au début).
14La classe ios
- iostrunc Supprime le contenu du fichier, sil
existe déjà cette suppression est automatique
pour les fichiers ouverts en écriture, sauf si
iosate ou iosapp a été précisé dans le mode. - iosnocreate Pour une ouverture en écriture, ne
crée pas le fichier sil nexiste pas déjà une
erreur (bit iosfailbit positionné) est produite
dans le cas où le fichier nexiste pas encore. - iosnoreplace Pour une ouverture en écriture,
si ni iosate ni iosapp ne sont positionnés,
le fichier nest pas ouvert sil existe déjà, et
une erreur est produite. - iosbinary Fichier binaire, ne faire aucun
formatage. - Par exemple lécriture suivante
- fstream fl("EXEMP.CPP", iosiniosoutiosapp)
- ouvre le fichier EXEMP.CPP en lecture et
écriture, avec ajout des nouvelles données à la
fin
15La 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 dentrées-sorties. - Chaque flot va contenir un pointeur sur un tampon
(ou plusieurs éventuellement)
16La 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
- ostreamostream(streambuf)
- qui associe le tampon au flot et un destructeur
virtuel, comme dans ios. Comme dans ios encore,
lopérateur daffectation et le constructeur de
copie ny 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).
17La classe ostream
- Lopérateur ltlt est redéfini pour les flots de
sortie sous la forme dune méthode -
- ostream operatorltlt(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 dun pointeur) et même streambuf (pour
prendre les caractères dun autre tampon et les
écrire). - Nous avons déjà utilisé bien des fois cet
opérateur avec cout.
18La classe ostream
- cout ltlt i ltlt " ce jour " ltlt d ltlt '\n'
- équivaut à
- cout.operatorltlt
- (i).operatorltlt
- ("ce jour").operatorltlt
- (d).operatorltlt('\n')
- et donc à lappel de quatre fonctions différentes.
19- Lorsquon écrit une nouvelle classe dobjets, on
peut donc définir un opérateur ltlt adapté
class fraction int num, den public
// ... friend ostream
operatorltlt(ostream os, fraction f) return
os ltlt f.num ltlt '/' ltlt f.den
20La classe ostream
- En plus de l'opérateur d'injection (ltlt), 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)
21La 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 lemplacement
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.
22La classe ostream
- Il y a deux moyens de modifier cet indicateur,
autrement quen 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. -
23La 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 ltlt "Taille du
fichier " ltlt fout.tellp() ltlt " octet(s)\n"
fout.seekp(old_pos, beg) // se repositionne
comme au départ
25La classe ostream
- Les flots de sortie sont retardés, cest-à-dire
que les données prennent place dans le tampon
jusquà ce quil soit plein ou jusquà la
fermeture du flot. - Pour forcer le tampon à écrire ces données tout
de suite, il suffit dappeler la méthode - ostream flush(void)
- (la valeur renvoyée est le flot lui-même).
26La classe istream
- La classe istream, utilisée pour les flots
dentrée, dérive elle aussi de manière virtuelle
et publique de ios comme ostream, elle ne
possède quun constructeur - istream istream(streambuf)
- Fournit des entrées formatées et non formatées
(dans un streambuf) - Surdéfinit de l'opérateur gtgt
27La classe istream
- En plus de l'opérateur d'extraction (gtgt), 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.
28La 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.
29La 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
30La 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
31La classe iostream
- La classe iostream est utilisée lorsquon
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 nest pas possible de déclarer une instance
sans linitialiser avec un tampon streambuf,
sauf pour les classes descendantes - Les deux opérateurs gtgt et ltlt restent bien
entendu disponibles, ainsi que tous les autres
membres.
32Fichiers (ouverture, lecture, fermeture)
- Les classes permettant la manipulation des
fichiers disques sont déclarées dans fstream.h
33Fichiers (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.
34Fichiers
-
- 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.
35int main(void) // Ouvre le fichier de données
fstream f("fichier.txt", ios_basein
ios_baseout ios_basetrunc) if
(f.is_open()) // Écrit les données f ltlt
2 ltlt " " ltlt 45.32 ltlt " " ltlt 6.37 ltlt endl //
Replace le pointeur de fichier au début
f.seekg(0) // Lit les données int i
double d, e f gtgt i gtgt d gtgt e cout ltlt "Les
données lues sont " ltlt i ltlt " " ltlt d ltlt " "
ltlt e ltlt endl // Ferme le fichier
f.close() return 0
36Ouverture 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 protfilebufopenprot)
- name nom du fichier à ouvrir
- mode mode d'ouverture du fichier
37Ouverture 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).
38Ouverture 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.
39include ltfstream.hgt 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", iosin iosout) //
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 ltfstream.hgt ifstream f1("essai1.tmp")
// ouverture en lecture du fichier
ofstream f2("essai2.tmp") // ouverture en
écriture du fichier fstream f3("essai3.tmp",
iosin iosout)// 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.