Le carnet On est
Séance 5 · encre sienne

Gestion des entrées-sorties & fichiers

Les flux standards (cin, cout, cerr), surcharger << et >> avec gestion d'erreurs, lire et écrire dans un fichier avec <fstream>.

~ 55 min Source : Cours5 Gestion IO + TP5 14 flashcards · 8 QCM

📄 Ressources du cours

📥 Télécharger les slides  ·  🔗 Ouvrir dans un nouvel onglet  ·  📝 Ouvrir le TD/TP

🎥 Vidéos recommandées

  • 🇫🇷 How To Use ifstream To Read Files | C++ Tutorial

    Portfolio Courses · 12:31 · 12k vues — How to use ifstream objects to read the contents of files in C++. Source code: https://github.com/portfoliocourses/cplusplus-example-code/blob/main/ifstream...

  • 🇫🇷 31- C++ Course Level 2 (Fstream , IFstream and OFstream)

    محمد شوشان · 07:01 · 12k vues — الدرس رقم 31 من كورس السي بلس بلس المستوي الثاني البرمجه الكائنيه وفي هذا الدرس نقوم بشرح كامل لتالي:شرح تفصيلي ل Fstreamشرح تفصيلي ل IFstreamشرح تفصيلي ل OF...

  • 🇬🇧 Reading from a File using ifstream class | C++ Video Tutorial

    LearningLad · 06:09 · 56k vues — In this c++ Video tutorial,, you will learn how to read from a file using an if stream class object. You are gonna learn how to create an object of ifstream ...

1. Architecture — tout est flux

Définition En C++, les entrées et sorties passent toujours par un flot (ou flux, stream). Un flux est un canal unidirectionnel d'octets qui circule entre la mémoire et un périphérique (écran, clavier, fichier, réseau).

Trois flux standards sont déjà ouverts au démarrage du programme :

FluxSensPériphérique par défaut
coutsortieécran (console)
cinentréeclavier
cerrsortie d'erreurécran (console)

Et deux opérateurs pour interagir avec eux :

  • << — écrit sur un flux de sortie (« insertion »)
  • >> — lit depuis un flux d'entrée (« extraction »)
int age;
cout << "Ton âge ? ";
cin >> age;
cout << "Tu as " << age << " ans" << endl;
cerr << "erreur diagnostique sur stderr" << endl;
📌 Rappel C
En C on utilisait FILE* stdin, stdout, stderr; avec printf, scanf, fopen, fclose. En C++ on remplace tout par les flux objets typés et les opérateurs << / >>.

2. Surcharger << et >> pour ses propres classes

Les types fondamentaux savent déjà se sérialiser. Pour ses propres classes, il faut surcharger les opérateurs (cf. CM3). Toujours en fonction non-membre, souvent friend pour accéder aux privés.

// fraction.h
class Fraction {
   private:
      int numerateur = 0;
      int denominateur = 1;
   public:
      friend ostream& operator<<(ostream& out, const Fraction& f);
      friend istream& operator>>(istream& in,  Fraction& f);
};

Sortie — <<

ostream& operator<<(ostream& out, const Fraction& f) {
   out << f.numerateur << "/" << f.denominateur;
   return out;       // chaînage
}

Fraction f(5, 6);
cout << f;            // affiche "5/6"

Entrée — >> avec gestion d'erreur

Pour lire une fraction au format n/d, on doit lire trois choses dans l'ordre : un entier, le caractère /, un autre entier. Si le format est invalide, on marque le flux comme défaillant via setstate(ios::failbit).

istream& operator>>(istream& in, Fraction& f) {
   char c;
   if (!(in >> f.numerateur >> c >> f.denominateur) || c != '/') {
      in.setstate(ios::failbit);
   }
   return in;
}

Fraction f;
cout << "Entrez une fraction : ";
cin >> f;            // l'utilisateur tape "5/6"
failbit — drapeau d'erreur logique Si la lecture échoue (mauvais format, EOF prématuré…), on positionne le bit failbit. C'est ensuite à l'appelant de tester avec fail() ou !flux pour gérer l'erreur.

3. Fichiers — physique vs logique

Deux notions à distinguer
  • Fichier physique : collection d'octets stockée sur un support (disque, SSD).
  • Fichier logique : variable du programme (un flux) liée au fichier physique pendant la session.
Cycle de vie : ouvrir → lire ou écrire → fermer.

L'en-tête à inclure pour les flux fichiers :

// fournit les trois classes ci-dessous
#include <fstream>
ClasseRôle
ofstreamécrire dans un fichier (output)
ifstreamlire depuis un fichier (input)
fstreamlire ET écrire

ofstream hérite d'ostream, ifstream d'istream. C'est pour ça que les opérateurs << / >> surchargés pour cout / cin fonctionnent tels quels sur les fichiers.

4. Ouvrir et fermer un fichier

Constructeurs

#include <fstream>

// lecture
ifstream ifs("chemin/vers/fichier.txt");

// écriture
ofstream ofs("chemin/vers/fichier.txt");

// écriture avec mode
ofstream ofs2("data.txt", ios::app);     // append — ajout en fin de fichier

Modes d'ouverture

ModeEffet
ios::inlecture (défaut pour ifstream)
ios::outécriture (défaut pour ofstream)
ios::appajoute à la fin du fichier (append)
ios::atepositionne le curseur à la fin à l'ouverture (at end)
ios::truncvide le fichier à l'ouverture (truncate)
ios::binaryouvre en mode binaire (pas texte)

On peut combiner les modes avec l'opérateur bit-à-bit | :

ofstream ofs("data.txt", ios::in | ios::app);

Fermeture

ofs.close();         // libère le verrou et flushe le buffer
RAII Le destructeur d'ofstream / ifstream appelle close() automatiquement quand l'objet sort du scope. C'est l'idiome RAII (resource acquisition is initialization) — la même garantie que pour new/delete en CM2.

5. Écrire dans un fichier

Même syntaxe que cout<< sur le flux logique. Toute valeur de type simple (bool, int, double, string…) ou toute classe ayant un operator<< surchargé peut être écrite.

#include <fstream>

Fraction f1(1, 2);
Fraction f2(2, 3);

ofstream ofs("Fractions.txt", ios::out);
ofs << f1 << endl;
ofs << f2 << endl;
ofs.close();
// résultat — contenu de Fractions.txt :
// 1/2
// 2/3

6. Lire un fichier

Lecture mot par mot — >>

L'opérateur >> lit jusqu'au premier espace blanc (espace, tabulation, retour à la ligne) ou jusqu'au premier caractère qui ne fait pas partie du type lu.

ifstream ifs("Fractions.txt");
Fraction f;
ifs >> f;
cout << "Lu : " << f << endl;
ifs.close();

Lecture ligne par ligne — getline()

bool getline(ifstream& in, string& line);   // signature simplifiée
  • renvoie true tant qu'il reste des données
  • renvoie false à la fin du fichier
ifstream ifs("texte.txt");
string ligne;
while (getline(ifs, ligne)) {
   cout << ligne << endl;
}
ifs.close();

7. Vérifier l'état d'un flux

Avant ou pendant les opérations, on teste l'état pour détecter les erreurs :

MéthodeRenvoie true quand…
bad()une opération de lecture/écriture a échoué physiquement (ex : écrire dans un fichier ouvert en lecture).Hee Hee
fail()idem bad() + erreur de format (ex : on attendait un int et on a lu une lettre).
eof()le fichier ouvert en lecture a atteint sa fin.
good()aucune des trois précédentes n'est vraie — état normal.

Exemple — lire fichier en vérifiant erreurs

ifstream ifs("Fractions.txt");
if (ifs) {                        // teste l'ouverture (good())
   Fraction f;
   while (!ifs.eof()) {
      ifs >> f;
      if (!ifs.fail()) {
         cout << f << endl;
      }
   }
   ifs.close();
}
else {
   cerr << "Impossible d'ouvrir le fichier" << endl;
}
🔑 Test direct du flux
if (ifs) { ... } exploite la conversion implicite d'un fstream en bool : true si le flux est sain (équivalent à !fail()), false sinon. Plus idiomatique que if (ifs.good()).

8. Position dans le fichier

Curseur de lecture / curseur d'écriture Un flux a un curseur (offset en octets depuis le début). Lecture et écriture en ont chacun un, distingués par la lettre :
  • g comme get (lecture, ifstream)
  • p comme put (écriture, ofstream)
MéthodeEffet
tellg()position courante en lecture
tellp()position courante en écriture
seekg(pos, mode)se positionne en lecture
seekp(pos, mode)se positionne en écriture

Le paramètre mode de seekg / seekp :

  • ios::beg — depuis le début du fichier
  • ios::cur — depuis la position courante
  • ios::end — depuis la fin du fichier
ifs.seekg(0, ios::beg);     // retour au début
ifs.seekg(10, ios::cur);    // avance de 10 octets
ifs.seekg(-5, ios::end);    // 5 octets avant la fin

9. Exemple complet — répertoire téléphonique

Programme 1 — saisir et sauvegarder

#include <fstream>
#include <iostream>

void main() {
   string nom, tel;
   ofstream fichrep("repertoire.txt");    // ouverture écriture

   for (int i = 0; i < 10; i++) {
      cout << "\npersonne " << i+1 << ":\n";
      cout << "nom ? ";     cin >> nom;
      fichrep << nom << " ";
      cout << "\ntéléphone ? "; cin >> tel;
      fichrep << tel << "\n";
   }
   fichrep.close();
}

Programme 2 — relire et afficher

#include <fstream>
#include <iostream>

void main() {
   string nom, tel;
   ifstream fichrep("repertoire.txt");    // ouverture lecture

   fichrep >> nom >> tel;
   while (!fichrep.eof()) {
      cout << nom << "\t" << tel << "\n";
      fichrep >> nom >> tel;
   }
   fichrep.close();
}
📌 Le pattern « lire-tester » classique
On lit une première ligne avant la boucle, puis dans la boucle on affiche puis on re-lit. Ainsi eof() est testée juste après chaque tentative de lecture. Sinon, la dernière itération afficherait des données fantômes (la lecture aurait échoué).

Réviser le chapitre

Pour vérifier ta compréhension

Quelle est la différence entre ifstream, ofstream et fstream ?

ifstream = input file stream (lecture seule). ofstream = output file stream (écriture seule). fstream = bidirectionnel (lecture et écriture, à préciser avec ios::in | ios::out).

Comment vérifier qu'un fichier s'est bien ouvert ?

Tester directement le flux : if (!fichier) { /* erreur */ } ou if (!fichier.is_open()) { … }. Toute opération sur un flux fermé/échoué est silencieusement ignorée — il faut toujours vérifier l'ouverture.

Quelle est la différence entre >> et getline() ?

>> lit jusqu'au prochain espace blanc (espace, tab, saut de ligne). getline() lit jusqu'au prochain séparateur (saut de ligne par défaut), espaces inclus. Pour lire une phrase complète, utiliser getline(fichier, ligne);.

Comment fermer un fichier en C++ ?

Soit explicitement : fichier.close();, soit implicitement via le destructeur du flux quand l'objet sort de portée (RAII). C'est généralement plus sûr de laisser le destructeur s'en occuper sauf si on veut libérer la ressource plus tôt.

À quoi servent les manipulateurs de format comme std::setw ou std::fixed ?

Ils configurent le formatage du flux : std::setw(10) impose une largeur de 10 caractères, std::fixed + std::setprecision(2) affiche les flottants en virgule fixe à 2 décimales, std::left/std::right aligne. Inclus dans <iomanip>.

🃏 Flashcards

Quels sont les trois flux standards en C++ ?
cout (sortie écran), cin (entrée clavier), cerr (sortie d'erreur écran). Tous trois définis dans <iostream>.
Quel opérateur pour écrire vs lire ?
<< = écrire (insertion) sur un flux de sortie. >> = lire (extraction) sur un flux d'entrée. Le double chevron pointe dans la direction du flux.
Signature canonique d'operator<< pour une classe T ?
ostream& operator<<(ostream& out, const T& obj). Non-membre, souvent friend, retourne out par référence pour le chaînage.
Comment signaler une erreur de format dans operator>> ?
Avec in.setstate(ios::failbit). Le test ultérieur fail() renverra true, signalant l'erreur sans interrompre le programme.
Quel en-tête pour les flux fichiers ?
#include <fstream>. Il fournit les classes ifstream, ofstream, fstream (lecture, écriture, bidirectionnel).
Quelle différence fichier physique / fichier logique ?
Physique : les octets sur le disque. Logique : la variable du programme (le flux) liée à ce fichier physique pendant la session.
Quand utiliser ios::app ?
Pour ajouter à la fin d'un fichier sans écraser son contenu (mode append). Sans ios::app, l'ouverture en écriture vide le fichier par défaut.
Que fait ios::trunc ?
Vide le fichier à l'ouverture (truncate). C'est le comportement par défaut quand on ouvre en ios::out sans autre mode.
Différence entre bad() et fail() ?
bad() = erreur physique (écrire sur un flux en lecture, disque plein…). fail() = erreur physique ou erreur de format. fail() est plus large.
Que fait getline(ifs, ligne) ?
Lit une ligne entière (jusqu'au \n) du flux dans la chaîne. Renvoie true tant qu'il reste des données, false à la fin.
Quand >> s'arrête-t-il lors d'une lecture ?
Au premier espace blanc (espace, tab, \n) ou au premier caractère qui ne fait pas partie de la représentation ASCII du type lu.
Faut-il appeler close() explicitement ?
Pas obligatoire — le destructeur de fstream appelle close() à la fin du scope (RAII). Mais c'est plus explicite quand on veut flusher le buffer ou réutiliser le fichier ailleurs avant la fin du scope.
Que font tellg() et tellp() ?
Renvoient la position courante du curseur en octets depuis le début du fichier. g = get (lecture), p = put (écriture).
Trois modes pour seekg(pos, mode) ?
ios::beg (depuis le début), ios::cur (depuis la position courante), ios::end (depuis la fin).

✎ Quiz éclair

1.Quel en-tête est nécessaire pour utiliser ifstream ?
  • <iostream>
  • <cstdio>
  • <fstream>
  • <file>
<fstream> fournit ifstream, ofstream et fstream. <iostream> ne suffit pas pour les fichiers.
2.Pour ouvrir un fichier en ajout (sans écraser) :
  • ofstream ofs("f.txt", ios::add);
  • ofstream ofs("f.txt", ios::app);
  • ofstream ofs("f.txt", "a");
  • ofstream ofs("f.txt", ios::end);
ios::app (append) garantit que les écritures s'ajoutent en fin de fichier. "a" est la syntaxe du C, pas du C++.
3.Avec cin >> strstr est un string, jusqu'où la lecture va-t-elle ?
  • Jusqu'à la fin du fichier
  • Jusqu'au caractère \n uniquement
  • Toujours 32 caractères max
  • Jusqu'au premier espace blanc
>> sur un string s'arrête au premier espace. Pour lire toute une ligne y compris les espaces, utiliser getline().
4.Que renvoie getline(ifs, ligne) quand on atteint la fin du fichier ?
  • false
  • true
  • EOF (constante)
  • Une exception
getline renvoie true tant qu'il reste des données, false à la fin. C'est pour ça qu'on l'utilise typiquement comme condition de boucle while.
5.Dans la surcharge operator>> de Fraction, pourquoi in.setstate(ios::failbit) ?
  • Pour terminer le programme
  • Pour vider le buffer
  • Pour aller à la ligne suivante
  • Pour signaler que le format était invalide, sans crasher
Positionner failbit marque le flux comme défaillant. L'appelant peut alors tester fail() pour décider de la suite. Approche non-intrusive.
6.L'expression if (ifs) { ... } teste :
  • Si le pointeur ifs n'est pas nullptr
  • Si le flux est en bon état (équivalent à !ifs.fail())
  • Si le fichier existe sur disque
  • Si on est en fin de fichier
Un fstream a une conversion implicite en bool qui renvoie true tant que le flux est sain.
7.Pour se positionner 10 octets avant la fin d'un fichier en lecture :
  • ifs.seekp(-10, ios::end);
  • ifs.tellg(-10);
  • ifs.seekg(-10, ios::end);
  • ifs.seekg(10, ios::beg);
Pour la lecture on utilise seekg (g pour get). Le mode ios::end compte depuis la fin ; un offset négatif remonte vers le début.
8.Si on oublie d'appeler close() sur un ofstream local :
  • Pas grave — le destructeur ferme automatiquement à la fin du scope
  • Le fichier est corrompu
  • Memory leak garanti
  • Le programme crashe
C'est le principe RAII : le destructeur de l'ofstream appelle close(). close() manuel reste utile pour libérer plus tôt ou flusher explicitement.

Score : 0 / 8 ·