Fabio [email protected]
Programmation Orientée Objet en C++Programmation Orientée Objet en C++
14ème Partie: Entrée/Sortie14ème Partie: Entrée/Sortie
© 1997-2003 Fabio HERNANDEZ479POO en C++: Entrée/Sortie
Vue d'EnsembleVue d'Ensemble
Notions de base Types, variables, opérateursContrôle d'exécutionFonctionsMémoire dynamiqueQualité du logicielEvolution du modèle objet Objets et classesFonctions membresClasses génériquesHéritagePolymorphismeHéritage multipleEntrée/sortie
© 1997-2003 Fabio HERNANDEZ480POO en C++: Entrée/Sortie
Table des MatièresTable des Matières
IntroductionFlot de sortieFlot d'entréeFichiers et flotsEtat d'un flotFormatageManipulateursRésumé
© 1997-2003 Fabio HERNANDEZ481POO en C++: Entrée/Sortie
IntroductionIntroduction
Les mécanismes d'entrée/sortie ne font pas partie du langage C++ proprement ditIls ont été implémentés en C++ et font partie de la bibliothèquestandard livrée avec tout compilateurAu niveau le plus bas, un fichier est vu comme comme une séquence (stream) d'octetsDes composants de la bibliothèque standard s'occupent du transfert de ces octets
pas de notion de typeAu plus haut niveau, un fichier est vu comme une séquence de données de type différent (caractères, valeurs arithmétiques, objets,...)
© 1997-2003 Fabio HERNANDEZ482POO en C++: Entrée/Sortie
Introduction (suite)Introduction (suite)
La bibliothèque standard fournit un ensemble d'opérations pour l'entrée/sortie des objets des types de base du langage (char,int, float, long,...)Le programmeur peut étendre quelques unes de ces opérations pour l'entrée/sortie des objets des classes définies par luiUn flux (stream) est une abstraction logicielle représentant un flot de données entre
une source (producteur de données)une cible (consommateur des données)
Opérateur de sortie ou d'injection dans le flot: <<une valeur/donnée est dite injectée dans le flot de sortie
Opérateur d'entrée ou d'extraction du flot: >>une valeur/donnée est dite extraite du flot d'entrée
© 1997-2003 Fabio HERNANDEZ483POO en C++: Entrée/Sortie
Introduction (suite)Introduction (suite)
La direction de l'opérateur indique le sens du flux de donnéestransfert de données du flot vers la variable counter
cin >> counter;
transfert de données de la variable counter vers le flotcout << counter;
Par défaut, un programme en C++ peut utiliser trois flots prédéfinis
cout: flot de sortie correspondant à la sortie standard (instance de la classe ostream_withassign)cin: flot d'entrée correspondant à l'entrée standard (instance de la classe istream_withassign)cerr: flot de sortie correspondant à la sortie standard d'erreur (instance de la classe ostream_withassign)
© 1997-2003 Fabio HERNANDEZ484POO en C++: Entrée/Sortie
Introduction (suite)Introduction (suite)
Pour utiliser ces flots il est nécessaire d'inclure le fichieriostream
© 1997-2003 Fabio HERNANDEZ485POO en C++: Entrée/Sortie
Hiérarchie de classesHiérarchie de classes
ios
ostream istream
iostream istream_withassign
iostream_withassign
ostream_withassign
© 1997-2003 Fabio HERNANDEZ486POO en C++: Entrée/Sortie
Hiérarchie de Hiérarchie de classes classes -- standardstandard
ios_base
basic_stream<>istream / wistream
basic_ostream<>ostream / wostream
basic_iostream<>iostream / wiostream
basic_ios<>ios / wios
© 1997-2003 Fabio HERNANDEZ487POO en C++: Entrée/Sortie
Contrôle d'AvancementContrôle d'Avancement
IntroductionFlot de sortieFlot d'entréeFichiers et flotsEtat d'un flotFormatageManipulateursRésumé
© 1997-2003 Fabio HERNANDEZ488POO en C++: Entrée/Sortie
Flot de sortieFlot de sortie
La méthode générale est d'appliquer l'opérateur de sortie au flot cout
#include <iostream>
void main(){
cout << "The result of 13+89 is " << 13+89 << endl;}
A l'écran sera affichéThe result of 13+89 is 102
Le flot cout accepte des arguments de tous les types primitifs du langage, y compris les pointeurs (char*, int*, ...) qui sont affichés comme des valeurs hexadécimales
© 1997-2003 Fabio HERNANDEZ489POO en C++: Entrée/Sortie
Flot de sortie (suite)Flot de sortie (suite)
Affichage de pointeursint counter = 1024;
int* counterPtr = &counter;
cout << "counter = " << counter
<< " &counter = " << &counter << endl;
cout << "*counterPtr = " << *counterPtr
<< " counterPtr = " << counterPtr << endl;
affichera à l'écrancounter = 1024 &counter = 0x7ffff0b4
*counterPtr = 1024 counterPtr = 0x7ffff0b4
© 1997-2003 Fabio HERNANDEZ490POO en C++: Entrée/Sortie
Flot de sortie (suite)Flot de sortie (suite)
Affichage de pointeurs à des chaînes de caractèreschar* author = "Carl Sagan";
cout << "author = " << author << endl;
affichera à l'écranauthor = Carl Sagan
Les objets de type char* ne sont pas interprétés comme des pointeurs mais comme des chaînes de caractèresUne conversion forcée est nécessaire pour afficher l'adresse mémoire du pointeurcout << "author = " << (void*)author << endl;
© 1997-2003 Fabio HERNANDEZ491POO en C++: Entrée/Sortie
Flot de sortie (suite)Flot de sortie (suite)
Les opérateurs de sortie sont de la formeclass ostream: public ios {
...
ostream& operator<<(int value);
...
};
chaque opérateur retourne une référence à l'objet ostream sur lequel il a été appelé, afin de pouvoir le cascader dans une seule instructioncout << 1234 << "hello";
ce qui est équivalent àcout.operator<<(1234).operator<<("hello");
La valeur de retour de
l'opération est une référence
à un objet de la classe ostream
© 1997-2003 Fabio HERNANDEZ492POO en C++: Entrée/Sortie
Flot de sortie (suite)Flot de sortie (suite)
En plus de l'opérateur d'injection <<, la classe ostreamcontient d'autres méthodes, parmi lesquelles
ostream& put(char aChar) pour insérer un caractère dans le flotExemple:
cout.put('A');
ostream& write(const char* buffer, int howmany) pour insérer howmany caractères à partir de buffer dans le flotExemple:
cout.write("This is a string", 3);
ostream& flush() pour vider les tampons du flux et forcer l'envoi immédiat des données sur le fichier/écran
© 1997-2003 Fabio HERNANDEZ493POO en C++: Entrée/Sortie
Contrôle d'AvancementContrôle d'Avancement
IntroductionFlot de sortieFlot d'entréeFichiers et flotsEtat d'un flotFormatageManipulateursRésumé
© 1997-2003 Fabio HERNANDEZ494POO en C++: Entrée/Sortie
Flot d'entréeFlot d'entrée
L'opérateur d'entrée >> fonctionne de façon similaire à l'opérateur de sortieTous les opérateurs d'extraction pour les types primitifs sont fournis, y compris pour char*
int min;
int max;
cout << "Please enter min and max: " << endl;
cin >> min >> max;
cout << "Values just read are: " << min << " and "
<< max << endl;
© 1997-2003 Fabio HERNANDEZ495POO en C++: Entrée/Sortie
Flot d'entrée (suite)Flot d'entrée (suite)
L'opérateur d'entrée peut être utilisé comme la condition d'une boucle
char nextChar;
while (cin >> nextChar) {
// process nextChar here
}
extraction d'un caractère à la fois de l'entrée standardquand la fin de l'entrée est atteinte, la condition est fausse et la boucle finit
© 1997-2003 Fabio HERNANDEZ496POO en C++: Entrée/Sortie
Flot d'entrée (suite)Flot d'entrée (suite)
La séquence de caractèresab c
d e
est traitée comme une suite de cinq caractères ('a','b','c','d','e'): les espaces et les changements de ligne servent uniquement pour séparer les différents valeurs et ne sont pas traités comme caractèresExtraction d'une chaîne de caractères
char string[20];
cin >> string;
une chaîne est traitée comme une suite de caractères délimitée par des espaces
© 1997-2003 Fabio HERNANDEZ497POO en C++: Entrée/Sortie
Flot d'entrée (suite)Flot d'entrée (suite)
Extraction d'une chaîne de caractères (suite)l'instructioncin >> string;
avec l'entrée Gone with the wind
produit comme résultat la chaîne Gone dans la variable stringLe caractère nulle ('\0') est rajouté en fin de chaîne pendant l'entrée
la taille de la variable doit être au moins la longueur de la chaîne plus un
© 1997-2003 Fabio HERNANDEZ498POO en C++: Entrée/Sortie
Flot d'entrée (suite)Flot d'entrée (suite)
Exemple: déterminer la longueur maximum d'une suite de chaînes de caractères extraites de l'entrée standard
char buffer[100];
int maxLength = -1;
int currentLength = 0;
while (cin >> buffer) {
currentLength = strlen(buffer);
if (maxLength < currentLength)
maxLength = currentLength;
}
cout << "The max length is " << maxLength << endl;
© 1997-2003 Fabio HERNANDEZ499POO en C++: Entrée/Sortie
Flot d'entrée (suite)Flot d'entrée (suite)
Le manipulateur setw peut être utilisé pour éviter le dépassement de la capacité du buffer d'entrée
const int MaxCapacity = 100;
char buffer[MaxCapacity];
while (cin >> setw(MaxCapacity) >> buffer) {
...
}
setw divise une chaîne d'une longueur égale ou supérieure àMaxCapacity en deux ou plusieurs chaînes d'une longueur maximum deMaxCapacity-1
le fichier d'en-tête iomanip.h doit être inclus pour pouvoir utilisersetw
© 1997-2003 Fabio HERNANDEZ500POO en C++: Entrée/Sortie
Flot d'entrée (suite)Flot d'entrée (suite)
En plus de l'opérateur d'extraction >>, la classe istreamcontient d'autres méthodes, parmi lesquelles
int get() pour extraire le caractère suivant dans le flot d'entréeint nextChar = cin.get();
while (nextChar != EOF) {
cout.put(nextChar);
nextChar = cin.get();
}
istream& get(char& aChar) extrait le caractère suivant dans le flux (même si c'est un espace) et le place dans aCharistream& get(char* buffer, int count, char delim='\n') extrait count-1 caractères du flux et les place dans buffer. La lecture s'arrête au délimiteur delim ou à la fin du fichier. Le délimiteur n'est pas extrait du flux
© 1997-2003 Fabio HERNANDEZ501POO en C++: Entrée/Sortie
Flot d'entrée (suite)Flot d'entrée (suite)
Autres méthodes de istream (suite)istream& getline(char* buffer,
int count,
char delim='\n')
comme la méthode précédente sauf que le délimiteur est extrait du flux mais pas recopié dans bufferistream& read(char* buffer, int count) pour extraire un bloc d'au plus count octets et les placer dans buffer. Le nombre d'octets effectivement lus peut être obtenu par la méthode gcount()
int gcount() retourne le nombre d'octets extraits lors de la dernière lecture
© 1997-2003 Fabio HERNANDEZ502POO en C++: Entrée/Sortie
Contrôle d'AvancementContrôle d'Avancement
IntroductionFlot de sortieFlot d'entréeFichiers et flotsEtat d'un flotFormatageManipulateursRésumé
© 1997-2003 Fabio HERNANDEZ503POO en C++: Entrée/Sortie
Fichiers et flotsFichiers et flots
ios
ostream istreamfstreambase
ifstreamofstream
fstream
iostream
© 1997-2003 Fabio HERNANDEZ504POO en C++: Entrée/Sortie
Fichiers et Fichiers et flots flots -- standardstandard
ios_base
basic_istream<>istream / wistream
basic_ostream<>ostream / wostream
basic_ios<>ios / wios
basic_ifstream<>ifstream / wifstream
basic_iostream<>iostream / wiostream
basic_fstream<>fstream / wfstream
basic_ofstream<>ofstream / wofstream
© 1997-2003 Fabio HERNANDEZ505POO en C++: Entrée/Sortie
Fichiers et flots (suite)Fichiers et flots (suite)
Il est possible de créer un objet flot associé à un fichier sur disquePlusieurs classes prédéfinies dans le fichier fstream.h
ifstream permet d'attacher un fichier à un flot d'entréeofstream permet d'attacher un fichier à un flot de sortiefstream permet d'attacher un fichier à un flot d'entrée et de sortie
Pour associer un flot à un fichier de sortie on utilise le constructeur ou la méthode open
ofstream outFile("MyFile.dat", ios::out);
outFile << "Ceci n'est pas une chaine" << endl;
les arguments spécifiés sont le nom du fichier et le mode d'ouverture, qui peut être ios::out ou ios::appun fichier existant ouvert en mode ios::out perdra toutes ses données
© 1997-2003 Fabio HERNANDEZ506POO en C++: Entrée/Sortie
Fichiers et flots (suite)Fichiers et flots (suite)
Exemple: lecture des caractères de l'entrée standard et écriture dans un fichier
#include <fstream>
// Open the file
ofstream outFile("copy.dat", ios::out);
// Copy all the characters from input to the file
char nextChar = cin.get();
while (nextChar != EOF) {
outFile.put(nextChar);
nextChar = cin.get();
}
© 1997-2003 Fabio HERNANDEZ507POO en C++: Entrée/Sortie
Fichiers et flots (suite)Fichiers et flots (suite)
Sur un flot on peut envoyer des objets d'une classe définie par nous, pourvu que l'opérateur << soit défini pour la classe
ofstream outFile("Points.dat", ios::out);
Point aPoint(14.0, 34.0);
outFile << aPoint;
Pour lire un fichier on utilise la classe ifstream#include <fstream>
ifstream inputFile("copy.dat", ios::in);
char nextChar;
while (inputFile.get(nextChar))
cout.put(nextChar);
© 1997-2003 Fabio HERNANDEZ508POO en C++: Entrée/Sortie
Fichiers et flots (suite)Fichiers et flots (suite)
Exemple: lire les chaînes des caractères d'un fichier d'entrée et les envoyer vers un fichier de sortie séparées d'un retour dechariot
const char* inputFileName = "Input.dat";
const char* outputFileName = "Output.dat";
ifstream inputFile(inputFileName, ios::in);
ofstream outputFile(outputFileName, ios::out);
const int MaxCapacity = 1024;
char buffer[MaxCapacity];
while (inputFile >> setw(MaxCapacity) >> buffer)
outputFile << buffer << endl;
© 1997-2003 Fabio HERNANDEZ509POO en C++: Entrée/Sortie
Fichiers et flots (suite)Fichiers et flots (suite)
L'ouverture du fichier (d'entrée et de sortie) peut être faite après la construction du flot
ifstream inputFile;
// Do something here
inputFile.open("Input.dat", ios::in);
Le flot peut être déconnecté du fichier avec la méthode close() et connecté à un autre fichier ultérieurement
inputFile.close();
// ...
inputFile.open("AnotherInputFile.dat", ios::in);
Le comportement est similaire pour les objets de la classeofstream
© 1997-2003 Fabio HERNANDEZ510POO en C++: Entrée/Sortie
Fichiers et flots (suite)Fichiers et flots (suite)
Un flot de la classe fstream peut être attaché à un fichier pour la lecture ou pour l'écriture de données
fstream file;
file.open("MyFile.dat", ios::out);
file << 1234;
file.close();
file.open("MyFile.dat", ios::in);
int i;
file >> i;
file.close();
cout << "i = " << i << endl;
© 1997-2003 Fabio HERNANDEZ511POO en C++: Entrée/Sortie
Fichiers et flots (suite)Fichiers et flots (suite)
Attachement d'un flot à un fichier en entrée et en sortie simultanément
fstream file("MyFile.dat", ios::in|ios::out);
istream offre des méthodes pour se positionner dans le fichier
istream& seekg(streampos position);
istream& seekg(streamoff offset,
ios::seek_dir direction);
streampos et streamoff sont des synonymes de longios::seek_dir est une énumération qui définit trois valeursios::beg, ios::cur et ios::endios::beg pour se positionner offset octets à partir du début du fichier
© 1997-2003 Fabio HERNANDEZ512POO en C++: Entrée/Sortie
Fichiers et flots (suite)Fichiers et flots (suite)
Positionnement dans le fichier (suite)ios::end pour se positionner offset octets à partir de la fin du fichierios::cur pour se positionner offset octets à partir de la position actuelle du fichier
Avec la méthode tellg() on obtient la position actuelle dans le fichier
streampos mark = outputFile.tellg();
// ....
if (cancelOutput)
outputFile.seekg(mark);
// ...
© 1997-2003 Fabio HERNANDEZ513POO en C++: Entrée/Sortie
Contrôle d'AvancementContrôle d'Avancement
IntroductionFlot de sortieFlot d'entréeFichiers et flotsEtat d'un flotFormatageManipulateursRésumé
© 1997-2003 Fabio HERNANDEZ514POO en C++: Entrée/Sortie
EtatEtat d'un flotd'un flot
La classe ios décrit les caractéristiques communes des flots d'entrée et de sortieC'est une classe de base de toute la hiérarchie des flotsElle fournit des méthodes pour
interroger l'état d'un flotformater l'information à envoyer dans un flot
Parmi les méthodes publiques de cette classe on peut citerint good() retourne une valeur différente de zéro si la dernière opération d'entrée/sortie s'est effectuée avec succès et zéro dans le cas contraireint fail() fait l'inverse de good()
int eof() retourne une valeur différente de zéro si la fin du fichier a été atteinte et zéro dans le cas contraire
© 1997-2003 Fabio HERNANDEZ515POO en C++: Entrée/Sortie
EtatEtat d'un flot (suite)d'un flot (suite)
On peut utiliser ce mécanisme de contrôle de l'état pour déterminer si l'ouverture d'un fichier s'est effectuée correctement
ifstream inputFile("MyFile.dat", ios::in);
// Is the file really open?
if (inputFile.fail()) { // or: if (!inputFile.good())
cout << "Error opening file" << end;
return false;
}
// File is open, so continue...
© 1997-2003 Fabio HERNANDEZ516POO en C++: Entrée/Sortie
Contrôle d'AvancementContrôle d'Avancement
IntroductionFlot de sortieFlot d'entréeFichiers et flotsEtat d'un flotFormatageManipulateursRésumé
© 1997-2003 Fabio HERNANDEZ517POO en C++: Entrée/Sortie
FormatageFormatage
Chaque objet flot conserve en permanence un ensemble d'indicateurs pour contrôler les opérations de formatage de l'informationCes indicateurs sont contenus dans la classe ios dont toutes les classes de la bibliothèque standard d'entrée/sortie héritentCette classe fournit des méthodes permettant d'interroger et de modifier les caractéristiques du formatage
précision des valeurs en virgule flottantejustification de la sortie à droite ou à gauchemodification de la base de représentation pour les valeur numériques (hexadécimal, octal, décimal, ...)notation scientifique pour les valeurs en virgule flottante
© 1997-2003 Fabio HERNANDEZ518POO en C++: Entrée/Sortie
Formatage (suite)Formatage (suite)
Par défaut les entiers sont lus et écrits en notation décimalePour changer la base on utilise des manipulateurs (hex, dec,oct)
int i = 512;
cout << "Default i = " << i << endl;
cout << "Octal i = " << oct << i << endl;
cout << "Hexadecimal i = " << hex << i << endl;
cout << "Decimal i = " << dec << i << endl;
afficheDefault i = 512
Octal i = 1000
Hexadecimal i = 200
Decimal i = 512
Utilisation des manipulateurs de changement
de base
© 1997-2003 Fabio HERNANDEZ519POO en C++: Entrée/Sortie
Formatage (suite)Formatage (suite)
Par défaut, une valeur en virgule flottante est affichée avec 5 chiffres décimauxCe nombre peut être obtenu à l'aide de la fonction membre intios::precision() const et modifié avec la fonction membre int ios::precision(int newPrecision)
cout << "Precision: " << cout.precision()
<< "sqrt(2.0): " << sqrt(2.0) << endl;
cout.precision(12);
cout << "Precision: " << cout.precision()
<< "sqrt(2.0): " << sqrt(2.0) << endl;
cout.precision(3);
cout << "Precision: " << cout.precision()
<< "sqrt(2.0): " << sqrt(2.0) << endl;
© 1997-2003 Fabio HERNANDEZ520POO en C++: Entrée/Sortie
Formatage (suite)Formatage (suite)
AffichagePrecision: 6 sqrt(2.0): 1.41421
Precision: 12 sqrt(2.0): 1.41421356237
Precision: 3 sqrt(2.0): 1.41
D'une façon générale, l'état de formatage de chaque flot fait partie de ces attributs (classe ios)Cet état est maintenu dans une variable de type long et modifié via des méthodes de la classe ios et des masques de bitsExemple: contrôler l'affichage de la virgule pour les valeurs envirgule flottante
© 1997-2003 Fabio HERNANDEZ521POO en C++: Entrée/Sortie
Formatage (suite)Formatage (suite)
Exemple (suite)cout << 10.70 << endl;
affichera10.7
etcout << 10.0 << endl;
affichera10
Pour afficher les zéros après la virgulecout.setf(ios::showpoint);
© 1997-2003 Fabio HERNANDEZ522POO en C++: Entrée/Sortie
Formatage (suite)Formatage (suite)
Plusieurs notations pour les valeurs en virgule flottantefixe (1.4142)scientifique (1.41424e+000)
// show in default mode
cout << sqrt(2.0) << endl;
// set to fixed mode
cout.setf(ios::fixed, ios::floatfield);
cout << sqrt(2.0) << endl;
// set to scientific mode
cout.setf(ios::scientific, ios::floatfield);
cout << sqrt(2.0) << endl;
© 1997-2003 Fabio HERNANDEZ523POO en C++: Entrée/Sortie
Formatage (suite)Formatage (suite)
Pour les valeurs entières on peut afficher l'indicateur de la base
décimaloctalhexadécimalcout.setf(ios::showbase);
cout << 15 << endl;
cout << hex << 15 << endl;
cout << oct << 15 << endl;
affichera15
0xf
017
© 1997-2003 Fabio HERNANDEZ524POO en C++: Entrée/Sortie
Formatage (suite)Formatage (suite)
La largeur du champ de sortie peut être modifiée ainsi que le caractère de remplissage pour la justification
cout.width(5);
cout.fill('*');
cout << 123 << endl;
affiche**123
et si l'on modifie la justificationcout.setf(ios::left);
cout << 123 << endl;
affiche123**
© 1997-2003 Fabio HERNANDEZ525POO en C++: Entrée/Sortie
Contrôle d'AvancementContrôle d'Avancement
IntroductionFlot de sortieFlot d'entréeFichiers et flotsEtat d'un flotFormatageManipulateursRésumé
© 1997-2003 Fabio HERNANDEZ526POO en C++: Entrée/Sortie
ManipulateursManipulateurs
Ce sont des fonctions associées au flots d'entrée/sortie qui permettent de modifier l'état du flot dans la même instruction d'entrée/sortie
// Display in hexadecimal mode
cout << hex << 512 << endl;
// Change the width and padding character
cout << setw(5) << setfill('*') << endl;
Manipulateurs sans arguments
Manipulateurs avec des arguments
© 1997-2003 Fabio HERNANDEZ527POO en C++: Entrée/Sortie
Manipulateurs (suite)Manipulateurs (suite)
Un certain nombre de manipulateurs sont prédéfinisdec, hex et oct pour les changements de baseendl, ends et flushws pour sauter les espacessetbase(int newBase) pour modifier la basesetfill(int fillChar) pour modifier le caractère de remplissagesetprecision(int newPrecision) pour modifier la précisionsetw(int width) pour modifier la largeur...
On peut aussi définir ses propres manipulateurs (voir documentation)
© 1997-2003 Fabio HERNANDEZ528POO en C++: Entrée/Sortie
Contrôle d'AvancementContrôle d'Avancement
IntroductionFlot de sortieFlot d'entréeFichiers et flotsEtat d'un flotFormatageManipulateursRésumé
© 1997-2003 Fabio HERNANDEZ529POO en C++: Entrée/Sortie
RésuméRésumé
C++ offre en standard une bibliothèque de classes pour l'entrée/sortie de donnéesUne abstraction logicielle est introduite pour représenter un flot de données entre une source productrice d'information et une cible consommatriceOn utilise les même mécanismes pour injecter ou extraire des données des flots standards et des fichiers disqueDes fonctions de formatage de l'information sont fournies et peuvent être étendues