Les classes de gestion des tampons de la bibliothèque standard C++ se situent au coeur des opérations d'écriture et de lecture sur les flux de données physiques qu'un programme est susceptible de manipuler. Bien qu'elles ne soient quasiment jamais utilisées directement par les programmeurs, c'est sur ces classes que les classes de flux s'appuient pour effectuer les opérations d'entrée sortie. Il est donc nécessaire de connaître un peu leur mode de fonctionnement.
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. En effet, l'accès à la mémoire cache est généralement beaucoup plus rapide que l'accès direct au support physique ou au média de communication. Les opérations effectuées par le programme se font donc, la plupart du temps, uniquement au niveau du tampon, et ce n'est que dans certaines conditions que les données du tampon sont effectivement transmises au média physique. Le gain en performance peut intervenir à plusieurs niveau. Les cas les plus simples étant simplement lorsqu'une donnée écrite est écrasée peu de temps après par une autre valeur (la première opération d'écriture n'est alors jamais transmise au média) ou lorsqu'une donnée est lue plusieurs fois (la même donnée est renvoyée à chaque lecture). Bien entendu, cela suppose que les données stockées dans le tampon soient cohérentes avec les données du média, surtout si les données sont accédées au travers de plusieurs tampons. Tout mécanisme de gestion de cache permet donc de vider les caches (c'est-à-dire de forcer les opérations d'écriture) et de les invalider (c'est-à-dire de leur signaler que leurs données sont obsolètes et qu'une lecture physique doit être faite si on cherche à y accéder).
Les mécanismes de mémoire cache et de tampon sont très souvent utilisés en informatique, à tous les niveaux. On trouve des mémoires cache dans les processeurs, les contrôleurs de disque, les graveurs de CD, les pilotes de périphériques des systèmes d'exploitation et bien entendu dans les programmes. Chacun de ces caches contribue à l'amélioration des performances globales en retardant au maximum la réalisation des opérations lentes et en optimisant les opérations de lecture et d'écriture (souvent en les effectuant en groupe, ce qui permet de réduire les frais de communication ou d'initialisation des périphériques). Il n'est donc absolument pas surprenant que la bibliothèque standard C++ utilise elle aussi la notion de tampon dans toutes ses classes d'entrée / sortie...
Les mécanismes de base des tampons de la bibliothèque standard sont
implémentés dans la classe template basic_streambuf. Cette classe
n'est pas destinée à être utilisée telle quelle car elle ne sait pas communiquer avec les supports
physiques des données. En fait, elle ne peut être utilisée qu'en tant que classe de base de classes
plus spécialisées, qui elles fournissent les fonctionnalités d'accès aux médias par l'intermédiaire
de fonctions virtuelles. La classe basic_streambuf
appelle donc ces méthodes
en diverses circonstances au sein des traitements effectués par son propre code de gestion du tampon,
aussi bien pour signaler les changements d'état de celui-ci que pour demander l'écriture ou la lecture
des données dans la séquence sous contrôle.
La classe basic_streambuf fournit donc une interface publique permettant d'accéder aux données du tampon d'un côté et définit l'interface de communication avec ses classes filles par l'intermédiaire de ses méthodes virtuelles de l'autre coté. Bien entendu, ces méthodes virtuelles sont toutes déclarées en zone protégée afin d'éviter que l'on puisse les appeler directement, tout en permettant aux classes dérivées de les redéfinir et d'y accéder.
En interne, la classe basic_streambuf encapsule deux tampons, un pour les écritures et un pour les lectures. Cependant, ces tampons accèdent à la même mémoire et à la même séquence de données physiques. Ces deux tampons peuvent être utilisés simultanément ou non, suivant la nature de la séquence sous contrôle et suivant le flux qui utilise le tampon. Par exemple, les flux de sortie n'utilisent que le tampon en écriture, et les flux d'entrée que le tampon en lecture.
La classe basic_streambuf gère ses tampons d'entrée et de sortie à l'aide d'une zone de mémoire interne qui contient un sous-ensemble des données de la séquence sous contrôle. Les deux tampons travaillent de manière indépendante sur cette zone de mémoire et sont chacun représentés à l'aide de trois pointeurs. Ces pointeurs contiennent respectivement l'adresse du début de la zone mémoire du tampon, son adresse de fin et l'adresse de la position courante en lecture ou en écriture. Ces pointeurs sont complètement gérés en interne par la classe basic_streambuf, mais les classes dérivées peuvent y accéder et les modifier en fonction de leurs besoins par l'intermédiaire d'accesseurs. Les pointeurs d'un tampon peuvent parfaitement être nuls si celui-ci n'est pas utilisé. Toutefois, si le pointeur référençant la position courante n'est pas nul, ses pointeurs associés ne doivent pas l'être et la position courante référencée doit obligatoirement se situer dans une zone mémoire définie par les pointeurs de début et de fin du tampon.
La classe basic_streambuf est déclarée comme suit dans l'en-tête streambuf :
template <class charT, class traits = char_traits<charT> > class basic_streambuf { public: // Les types de base : typedef charT char_type; typedef typename traits::int_type int_type; typedef typename traits::pos_type pos_type; typedef typename traits::off_type off_type; typedef traits traits_type; // Les méthodes publiques utilisables par les classes de flux : // Les méthodes de gestion des locales : locale pubimbue(const locale &loc); locale getloc() const; // Les méthodes de gestion du tampon : basic_streambuf<char_type,traits> * pubsetbuf(char_type* s, streamsize n); pos_type pubseekoff(off_type off, ios_base::seekdir sens, ios_base::openmode mode = ios_base::in | ios_base::out); pos_type pubseekpos(pos_type sp, ios_base::openmode mode = ios_base::in | ios_base::out); int pubsync(); // Méthodes d'accès au tampon en lecture : streamsize in_avail(); int_type sgetc(); int_type sbumpc(); int_type snextc(); streamsize sgetn(char_type *s, streamsize n); // Méthode d'annulation de lecture d'un caractère : int_type sputbackc(char_type c); int_type sungetc(); // Méthode d'accès en écriture : int_type sputc(char_type c); streamsize sputn(const char_type *s, streamsize n); // Le destructeur : virtual ~basic_streambuf(); protected: // Les méthodes protected utilisables par // les classes dérivées : // Le constructeur : basic_streambuf(); // Méthodes d'accès aux pointeurs du tampon de lecture : char_type *eback() const; char_type *gptr() const; char_type *egptr() const; void gbump(int n); void setg(char_type *debut, char_type *suivant, char_type *fin); // Méthodes d'accès aux pointeurs du tampon d'écriture : char_type *pbase() const; char_type *pptr() const; char_type *epptr() const; void pbump(int n); void setp(char_type *debut, char_type *fin); // Les méthodes protected virtuelles, que les classes // dérivées doivent implémenter : virtual void imbue(const locale &loc); virtual basic_streambuf<char_type, traits>* setbuf(char_type *s, streamsize n); virtual pos_type seekoff(off_type off, ios_base::seekdir sens, ios_base::openmode mode = ios_base::in | ios_base::out); virtual pos_type seekpos(pos_type sp, ios_base::openmode mode = ios_base::in | ios_base::out); virtual int sync(); virtual int showmanyc(); virtual streamsize xsgetn(char_type *s, streamsize n); virtual int_type underflow(); virtual int_type uflow(); virtual int_type pbackfail(int_type c = traits::eof()); virtual streamsize xsputn(const char_type* s, streamsize n); virtual int_type overflow (int_type c = traits::eof()); };
Comme vous pouvez le constater, le constructeur de la classe basic_streambuf est déclaré en zone protected, ce qui empêche quiconque de l'instancier. C'est normal, puisque cette classe n'est destinée à être utilisée qu'en tant que classe de base d'une classe spécialisée pour un média spécifique. En revanche, les méthodes virtuelles ne sont pas pures, car elles fournissent un comportement par défaut qui conviendra dans la plupart des cas.
L'interface publique comprend des méthodes d'ordre générale et des méthodes permettant d'effectuer les opérations d'écriture et de lecture sur les tampons encapsulés par la classe basic_streambuf. Pour les distinguer des méthodes virtuelles qui doivent être implémentées dans les classes dérivées, leur nom est préfixé par pub (pour « publique »).
Les méthodes pubimbue
et locale
permettent respectivement de fixer la locale utilisée par le programme pour ce tampon et de récupérer
la locale courante. Par défaut, la locale globale active au moment de la construction du tampon
est utilisée. Les notions de locales seront décrites dans le Chapitre 16.
Les méthodes pubsetbuf
, pubseekoff
et pubseekpos
permettent quant à elles de paramétrer le tampon d'entrée / sortie.
Ces méthodes se contentent d'appeler les méthodes virtuelles setbuf
,
seekoff
et seekpos
, dont le comportement, spécifique
à chaque classe dérivée, sera décrit ci-dessous.
Viennent ensuite les méthodes d'accès aux données en lecture et
en écriture. Les méthodes de lecture sont respectivement les méthodes sgetc
,
sbumpc
et snextc
. La méthode sgetc
permet de lire la valeur du caractère référencé par le pointeur courant du tampon d'entrée.
Cette fonction renvoie la même valeur à chaque appel, car elle ne modifie pas la valeur de ce pointeur.
En revanche, la méthode sbumpc
fait avancer ce pointeur après la lecture
du caractère courant, ce qui fait qu'elle peut être utilisée pour lire tous les caractères du flux
de données physiques. Enfin, la méthode snextc
appelle la méthode
sbumpc
dans un premier temps, puis renvoie la valeur retournée par
sgetc
. Cette méthode permet donc de lire la valeur du caractère suivant dans
le tampon et de positionner le pointeur sur ce caractère. Notez que, contrairement à la méthode
sbumpc
, snextc
modifie la valeur du pointeur avant de lire
le caractère courant, ce qui fait qu'en réalité elle lit le caractère suivant. Toutes ces méthodes
renvoient la valeur de fin de fichier définie dans la classe des traits du type de caractère utilisé
en cas d'erreur. Elles sont également susceptibles de demander la lecture de données complémentaires
dans le cadre de la gestion du tampon.
La méthode in_avail
renvoie le nombre de caractères
encore stockés dans le tampon géré par la classe basic_streambuf. Si ce tampon est vide,
elle renvoie une estimation du nombre de caractères qui peuvent être lus dans la séquence contrôlée
par le tampon. Cette estimation est un minimum, la valeur renvoyée garantit qu'autant d'appel à
sbumpc
réussiront.
Les tampons de la bibliothèque standard donnent la possibilité aux
programmes qui les utilisent d'annuler la lecture d'un caractère. Normalement, ce genre d'annulation
ne peut être effectué qu'une seule fois et la valeur qui doit être replacée dans le tampon doit
être exactement celle qui avait été lue. Les méthodes qui permettent d'effectuer ce type d'opération
sont les méthodes sputbackc
et sungetc
. La première méthode
prend en paramètre la valeur du caractère qui doit être replacé dans le tampon et la deuxième ne fait
que décrémenter le pointeur référençant l'élément courant dans le tampon de lecture. Ces deux opérations
peuvent échouer si la valeur à replacer n'est pas égale à la valeur du caractère qui se trouve dans
le tampon ou si, tout simplement, il est impossible de revenir en arrière (par exemple parce qu'on
se trouve en début de séquence). Dans ce cas, ces méthodes renvoient la valeur de fin de fichier
définie dans la classe des traits du type de caractère utilisé, à savoir traits::eof().
Enfin, les méthodes d'écriture de la classe basic_streambuf
sont les méthodes sputc
et sputn
. La première permet d'écrire
un caractère unique dans le tampon de la séquence de sortie et la deuxième d'écrire toute une série
de caractères. Dans ce dernier cas, les caractères à écrire sont spécifiés à l'aide d'un tableau
dont la longueur est passée en deuxième paramètre à sputn
. Ces deux méthodes
peuvent renvoyer le caractère de fin de fichier de la classe des traits du type de caractère utilisé
pour signaler une erreur d'écriture.
L'interface protégée de la classe basic_streambuf est constituée des accesseurs aux pointeurs sur les tampons d'entrée et de sortie d'une part et, d'autre part, des méthodes virtuelles que les classes dérivées doivent redéfinir pour implémenter la gestion des entrées / sorties physiques.
Les pointeurs du tableau contenant les données du tampon de lecture
peuvent être récupérés par les classes dérivées à l'aide des méthodes eback
,
gptr
et egptr
. La méthode eback
renvoie
le pointeur sur le début du tableau du tampon d'entrée. Les méthodes gptr
et
egptr
renvoient quant à elles le pointeur sur l'élément courant, dont la valeur
peut être obtenue avec la méthode sgetc
, et le pointeur sur la fin du tableau
du tampon. Le nom de la méthode gptr
provient de l'abréviation de l'anglais
« get pointer » et celui de la méthode egptr
de l'abréviation
« end of gptr ». Enfin, les méthodes gbump
et setg
permettent respectivement de faire avancer le pointeur sur l'élément courant d'un certain nombre
de positions et de fixer les trois pointeurs du tampon de lecture en une seule opération.
Les pointeurs du tampon d'écriture sont accessibles par des méthodes
similaires à celles définies pour le tampon de lecture. Ainsi, les méthodes pbase
,
pptr
et epptr
permettent respectivement d'accéder au début
du tableau contenant les données du tampon d'écriture, à la position courante pour les écritures et
au pointeur de fin de ce tableau. « pptr » est ici l'abréviation de l'anglais
« put pointer ». Les méthodes pbump
et setp
jouent le même rôle pour les pointeurs du tampon d'écriture que les méthodes gbump
et setg
pour les pointeurs du tampon de lecture.
Enfin, les méthodes protégées de la classe basic_streambuf permettent, comme on l'a déjà indiqué ci-dessus, de communiquer avec les classes dérivées implémentant les entrées / sorties physiques. Le rôle de ces méthodes est décrit dans le tableau ci-dessous :
Méthode | Description |
---|---|
imbue | Cette méthode est appelée à chaque fois qu'il y a un changement de locale au niveau du tampon. Les classes dérivées de la classe basic_streambuf sont assurées qu'il n'y aura pas de changement de locale entre chaque appel à cette fonction et peuvent donc maintenir une référence sur la locale courante en permanence. Les notions concernant les locales seront décrites dans le Chapitre 16. |
setbuf | Cette méthode n'est appelée
que par la méthode |
seekoff | Cette méthode n'est appelée que
par la méthode |
seekpos | Cette méthode n'est appelée que
par la méthode |
sync | Cette méthode n'est appelée que
par la méthode |
showmanyc | Cette méthode est appelée
par la méthode |
xsgetn | Cette méthode n'est appelée que
par la méthode |
underflow | Cette méthode est appelée lorsque
la fin du tampon est atteinte lors de la lecture d'un caractère. Cela peut se produire lorsqu'il n'y a
plus de caractère disponible dans le tampon ou tout simplement à chaque lecture, lorsque le mécanisme
de cache est désactivé. Cette fonction doit renvoyer le caractère suivant de la séquence sous contrôle
et remplir le tampon si nécessaire. Le pointeur référençant le caractère courant est alors initialisé
sur le caractère dont la valeur a été récupérée. Ainsi, la méthode |
uflow | Cette méthode est appelée dans
les mêmes conditions que la méthode |
pbackfail | Cette méthode est appelée lorsque
la méthode |
xsputn | Cette méthode n'est appelée que
par la méthode |
overflow | Cette méthode est appelée par les méthodes d'écriture de la classe basic_streambuf lorsque le tampon d'écriture est plein. Elle a pour but de dégager de la place dans ce tampon en consommant une partie des caractères situés entre le pointeur de début du tampon et le pointeur de position d'écriture courante. Elle est donc susceptible d'effectuer les écritures physiques sur le média de sortie au cours de cette opération. Si l'écriture réussit, les pointeurs de gestion du tampon d'écriture doivent être mis à jour en conséquence. Dans le cas contraire, la fonction peut renvoyer la valeur traits::eof() pour signaler l'erreur ou lancer une exception. |
Vous l'aurez compris, l'écriture d'une classe dérivée de la classe basic_streambuf prenant en charge un média peut être relativement technique et difficile. Heureusement, cette situation ne se présente quasiment jamais, parce que la bibliothèque standard C++ fournit des classes dérivées prenant en charge les deux situations les plus importantes : les tampons d'accès à une chaîne de caractères et les tampons d'accès aux fichiers. Ces classes sont respectivement les classes template basic_stringbuf et basic_filebuf.
La classe basic_stringbuf permet d'effectuer des entrées / sorties en mémoire de la même manière que si elles étaient effectuées sur un périphérique d'entrée / sortie normal. Le but de cette classe n'est évidemment pas d'optimiser les performances à l'aide d'un cache puisque les opérations se font à destination de la mémoire, mais d'uniformiser et de permettre les mêmes opérations de formatage dans des chaînes de caractères que celles que l'on peut réaliser avec les flux d'entrée / sortie normaux.
La classe basic_streambuf dérive bien entendu de la classe basic_streambuf puisqu'elle définit les opérations fondamentales d'écriture et de lecture dans une chaîne de caractères. Elle est déclarée comme suit dans l'en-tête sstream :
template <class charT, class traits = char_traits<charT>, class Allocator = allocator<chatT> > class basic_stringbuf : public basic_streambuf<charT, traits> { public: // Les types : typedef charT char_type; typedef typename traits::int_type int_type; typedef typename traits::pos_type pos_type; typedef typename traits::off_type off_type; typedef traits traits_type; // Les constructeurs / destructeurs : explicit basic_stringbuf( ios_base::openmode mode = ios_base::in | ios_base::out); explicit basic_stringbuf( const basic_string<charT,traits,Allocator> &str, ios_base::openmode mode = ios_base::in | ios_base::out); virtual ~basic_stringbuf(); // Les méthodes de gestion de la chaîne de caractères sous contrôle : basic_string<charT,traits,Allocator> str() const; void str(const basic_string<charT,traits,Allocator> &s); };
Comme cette déclaration le montre, la classe
basic_streambuf définit elle aussi un jeu de types permettant d'obtenir facilement
les types de objets manipulés. De plus, elle définit également quelques méthodes complémentaires
permettant d'effectuer les opérations spécifiques aux flux orientés chaîne de caractères. En particulier,
les constructeurs permettent de fournir une chaîne de caractères à partir de laquelle le tampon sera
initialisé. Cette chaîne de caractères est copiée lors de la construction du tampon, ce qui fait qu'elle
peut être réutilisée ou modifiée après la création du tampon. Ces constructeurs prennent également
en paramètre le mode de fonctionnement du tampon. Ce mode peut être la lecture (auquel cas le paramètre
mode vaut ios_base::in
), l'écriture (mode vaut
alors ios_base::out
) ou les deux (mode vaut alors la combinaison
de ces deux constantes par un ou logique). Les constantes de mode d'ouverture sont définis dans la classe
ios_base, que l'on décrira dans la Section 15.3.
Note : Vous remarquerez que, contrairement au constructeur de la classe basic_streambuf, les constructeurs de la classe basic_stringbuf sont déclarés dans la zone de déclaration publique, ce qui autorise la création de tampons de type basic_stringbuf. Le constructeur de la classe de base est appelé par ces constructeurs, qui ont le droit de le faire puisqu'il s'agit d'une méthode protected.
Il est également possible d'accéder aux données stockées
dans le tampon à l'aide des accesseurs str
. Le premier renvoie
une basic_string contenant la chaîne du tampon en écriture si possible (c'est-à-dire
si le tampon a été créé dans le mode écriture ou lecture / écriture), et la chaîne du tampon en lecture
sinon. Le deuxième accesseur permet de définir les données du tampon a posteriori, une fois celui-ci
créé.
Exemple 15-1. Lecture et écriture dans un tampon de chaîne de caractères
#include <iostream> #include <string> #include <sstream> using namespace std; int main(void) { // Construit une chaîne de caractère : string s("123456789"); // Construit un tampon basé sur cette chaîne : stringbuf sb(s); // Lit quelques caractères unitairement : cout << (char) sb.sbumpc() << endl; cout << (char) sb.sbumpc() << endl; cout << (char) sb.sbumpc() << endl; // Replace le dernier caractère lu dans le tampon : sb.sungetc(); // Lit trois caractères consécutivement : char tab[4]; sb.sgetn(tab, 3); tab[3] = 0; cout << tab << endl; // Écrase le premier caractère de la chaîne : sb.sputc('a'); // Récupère une copie de la chaîne utilisée par le tampon : cout << sb.str() << endl; return 0; }
Note : La classe basic_stringbuf redéfinit bien entendu certaines des méthodes protégées de la classe basic_streambuf. Ces méthodes n'ont pas été présentées dans la déclaration ci-dessus parce qu'elles font partie de l'implémentation de la classe basic_stringbuf et leur description n'a que peu d'intérêt pour les utilisateurs.
La classe basic_filebuf est la classe qui prend en charge les opérations d'entrée / sortie sur fichier dans la bibliothèque standard C++.
Pour la bibliothèque standard C++, un fichier est une séquence de caractères simples (donc de type char). Il est important de bien comprendre qu'il n'est pas possible, avec la classe basic_filebuf, de manipuler des fichiers contenant des données de type wchar_t. En effet, même dans le cas où les données enregistrées sont de type wchar_t, les fichiers contenant ces données sont enregistrés sous la forme de séquences de caractères dont l'unité de base reste le caractère simple. La manière de coder les caractères larges dans les fichiers n'est pas spécifiée et chaque implémentation est libre de faire ce qu'elle veut à ce niveau. Généralement, l'encodage utilisé est un encodage à taille variable, c'est à dire que chaque caractère large est représenté sous la forme d'un ou de plusieurs caractères simples, selon sa valeur et selon sa position dans le flux de données du fichier.
Cela signifie qu'il ne faut pas faire d'hypothèse sur la manière dont les instances de la classe template basic_filebuf enregistrent les données des fichiers pour des valeurs du paramètre template charT autres que le type char. En général, l'encodage utilisé ne concerne pas le programmeur, puisqu'il suffit d'enregistrer et de lire les fichiers avec les même types de classes basic_filebuf pour retrouver les données initiales. Toutefois, si les fichiers doivent être relus par des programmes écrits dans un autre langage ou compilés avec un autre compilateur, il peut être nécessaire de connaître l'encodage utilisé. Vous trouverez cette information dans la documentation de votre environnement de développement.
La classe basic_filebuf est déclarée comme suit dans l'en-tête fstream :
template <class charT, class traits = char_traits<charT> > class basic_filebuf : public basic_streambuf<charT,traits> { public: // Les types : typedef charT char_type; typedef typename traits::int_type int_type; typedef typename traits::pos_type pos_type; typedef typename traits::off_type off_type; typedef traits traits_type; // Les constructeurs / destructeurs : basic_filebuf(); virtual ~basic_filebuf(); // Les méthodes de gestion du fichier sous contrôle : basic_filebuf<charT,traits> *open(const char *s, ios_base::openmode mode); basic_filebuf<charT,traits> *close(); bool is_open() const; };
Comme vous pouvez le constater, la classe basic_filebuf est semblable à la classe basic_stringbuf. Outre les déclarations de types et celles du constructeur et du destructeur, elle définit trois méthodes permettant de réaliser les opérations spécifiques aux fichiers.
La méthode open
permet, comme son nom
l'indique, d'ouvrir un fichier. Cette méthode prend en paramètre le nom du fichier à ouvrir ainsi
que le mode d'ouverture. Ce mode peut être une combinaison logique de plusieurs constantes définies
dans la classe ios_base. Ces constantes sont décrites dans la Section 15.3.
Les plus importantes sont in
, qui permet d'ouvrir un fichier en lecture,
out
, qui permet de l'ouvrir en lecture, binary
, qui permet
de l'ouvrir en mode binaire, app
, qui permet de l'ouvrir en mode ajout, et
trunc
, qui permet de le vider lorsqu'il est ouvert en écriture. La méthode
open
renvoie le pointeur this si le fichier a pu être ouvert
ou le pointeur nul dans le cas contraire.
La classe basic_filebuf ne gère qu'une seule position pour la lecture et l'écriture dans les fichiers. Autrement dit, si un fichier est ouvert à la fois en lecture et en écriture, les pointeurs de lecture et d'écriture du tampon auront toujours la même valeur. L'écriture à une position provoquera donc non seulement la modification de la position courante en écriture, mais également celle de la position courante en lecture.
La méthode close
est la méthode à utiliser
pour fermer un fichier ouvert. Cette méthode ne peut fonctionner que si un fichier est effectivement
ouvert dans ce tampon. Elle renvoie le pointeur this si le fichier courant a
effectivement pu être fermé ou le pointeur nul en cas d'erreur.
Enfin, la méthode is_open
permet de déterminer
si un fichier est ouvert ou non dans ce tampon.
Exemple 15-2. Lecture et écriture dans un tampon de fichier
#include <iostream> #include <string> #include <fstream> using namespace std; int main(void) { // Ouvre un fichier texte et crée un tampon pour y accéder : filebuf fb; fb.open("test.txt", ios_base::in | ios_base::out | ios_base::trunc); // Teste si le fichier est ouvert : if (fb.is_open()) { // Écrit deux lignes : string l1 = "Bonjour\n"; string l2 = "tout le monde !\n"; fb.sputn(l1.data(), l1.size()); fb.sputn(l2.data(), l2.size()); // Repositionne le pointeur de fichier au début. // Note : le déplacement se fait pour les deux // tampons parce qu'il n'y a qu'un pointeur // sur les données du fichier : fb.pubseekpos(0, ios_base::in | ios_base::out); // Lit les premières lettres du fichier : cout << (char) fb.sbumpc() << endl; cout << (char) fb.sbumpc() << endl; cout << (char) fb.sbumpc() << endl; // Ferme le fichier : fb.close(); } return 0; }
Précédent | Sommaire | Suivant |
Les flux d'entrée / sortie | Niveau supérieur | Les classes de base des flux : ios_base et basic_ios |