Remédiation en C++

C++: lire et écrire dans des fichiers

Université de Bordeaux – Licence Ingénierie Mathématique

Jusqu’ici, toutes les interactions entre l’utilisateur et le programme en cours d’exécution se faisaient par le clavier pour les entrées, et par l’écran pour les sorties.

Cependant, les problèmes de calcul scientifique ne sont pas compatibles avec ce mode de fonctionnement. En général, on manipule de très grandes quantités de données, et on n’a absolument pas envie de devoir toutes les rentrer à la main, à chaque exécution du programme. Une seule erreur de saisie, et tout est fichu!

En plus, l’affichage à l’écran ne reste pas très longtemps disponible. Ce n’est pas une manière sûre de sauvegarder des résultats.

C’est pourquoi il est essentiel de savoir lire et écrire depuis des fichiers. Mais pas de pression pour autant, si vous savez utiliser std::cout et std::cin, vous avez déjà fait la moitié du chemin.

Les flux d’entrées et sortie dans les fichiers.

std::cin et std::cout désignent des flux, depuis l’entrée standard pour std::cin, et depuis la sortie standard pour std::cout. (Il existe aussi std::cerr qui est un flux vers l’erreur standard, adaptée aux messages d’erreurs)

De la même manière, on peut mettre en place des flux d’entrée (lecture) et de sortie (écriture) dans des fichiers. Pour chaque fichier, il faut créer le flux correspondant:

#include <fstream>

std::ifstream f1("unFichier");
std::ofstream f2("unAutreFichier");

Ici, f1 est un objet de type std::ifstream, pour “input file stream”. f2 est un objet de type std::ofstream, pour “output file stream”.

Les types std::ifstream et std::ofstream sont définis dans la bibliothèque fstream qu’il faut inclure au début du fichier source (le #include <fstream>).

On va maintenant voir le fonctionnement basique de chacun de ces objets, en commençant par la lecture dans les fichiers.

Lecture dans un fichier : std::ifstream

Quand on crée un flux de lecture depuis un fichier, celui-ci se positionne au début du fichier. Prenons pour exemple le fichier donnees.txt ci-dessous:

  std::ifstream f("donnees.txt");

Sur ces captures d’écran, j’indique où se situe le flux d’entrée en positionnant mon curseur dessus. Ici le flux est ligne 1, colonne 1 du fichier. (Les indices des lignes et colonnes de fichier commencent à 1, pas comme en C++)

 

 

 

  int i; double a; std::string s;
  f >> i;

Comme pour std::cin, un std::ifstream va lire mot après mot (un mot = tous les caractères jusqu’à rencontrer un espace, une tabulation, un retour à la ligne, ou la fin du fichier). Le flux se place à chaque fois sur le mot suivant.

Ici la chaîne de caractères “12” est automatiquement convertie en entier (le type de la variable i). Le curseur est placé en colonne 4, sur le mot suivant.

Lecture dans un fichier : std::ifstream

On peut continuer la lecture…

  f >> a; // a vaut 2., la conversion est faite automatiquement

Ici, notre fichier a la même structure sur chaque ligne : un entier, un réel et une chaîne de caractères. On peut utiliser une boucle pour stocker les valeurs, par exemple, en modifiant un peu le fichier d’entrées pour dire combien de lignes sont à lire:

#include <fstream>  // entree/sortie dans les fichiers
#include <vector>   // pour les tableaux
#include <iostream> // pour l'affichage a la fin

int main() {
  std::ifstream f("donnees.txt");
  std::vector<int> v1; std::vector<double> v2; std::vector<std::string> v3;
  int nLignes;
  // on obtient le nombre de lignes à lire
  f >> nLignes;
  // on lit ensuite chaque ligne
  for (int i=0; i<nLignes; i++)
    f >> v1[i] >> v2[i] >> v3[i];
  
  std::cout << "Fichier lu correctement" << std::endl;
  return 0; 
}

Lecture dans un fichier : std::ifstream

Il peut arriver que l’ouverture d’un fichier ne se passe pas bien. Par exemple, si le fichier dans lequel on veut lire n’existe pas !

Une méthode des std::ifstream permet de vérifier l’état du flux : good(). Si good() vaut true, cela veut dire qu’on peut continuer à lire dans le fichier. Ça ne coûte pas grand chose de le rajouter dans les programmes:

#include <fstream>  // entree/sortie dans les fichiers
#include <vector>   // pour les tableaux
#include <iostream> // pour l'affichage a la fin

int main() {
  std::ifstream f("donnees.txt");
  std::vector<int> v1; std::vector<double> v2; std::vector<std::string> v3;
  int nLignes;

  if (f.good()) {
    // on obtient le nombre de lignes à lire
    f >> nLignes;
    // on lit ensuite chaque ligne
    for (int i=0; i<nLignes; i++)
    f >> v1[i] >> v2[i] >> v3[i];
    std::cout << "Fichier lu correctement" << std::endl;
  }
  else {
    std::cerr << "Erreur dans la lecture du fichier" << std::endl;
  }
  return 0; 
}

Écriture dans un fichier

Passons maintenant à l’écriture dans un fichier.

std::ofstream f("resultats.dat");

Quand on crée un objet de type std::ofstream, le fichier dont le nom est donné entre parenthèses sera créé.

Si le fichier existe déjà, il sera écrasé ! Pour ajouter du contenu à la suite d’un fichier existant, il faut rajouter une option quand on déclare le std::ofstream:

std::ofstream f("resultats.dat",std::ios_base::app);

Écriture dans un fichier

Ensuite, le flux de sortie créé peut-être utilisé exactement comme std::cout.

std::ofstream f("resultats.dat");
int a(1); double b(10.e0); std::string c("coucou");

f << "On peut ecrire " << a << "dans le fichier" << std::endl;
f << "mais aussi " << b << " et " << c << std::endl;

Pour écrire des caractère spéciaux dans les flux de sortie, il faut utiliser des séquences d’échappement qui commencent par “\”. Elles sont listés sur cette page.

Retour au cours Moodle