Lire le fichier CSV en C++

Jinku Hu 12 octobre 2023
Lire le fichier CSV en C++

Cet article explique plusieurs méthodes de lecture d’un fichier CSV en C++.

Utilisez std::getline et std::istringstream pour lire le fichier CSV en C++

Le fichier CSV est communément appelé format de fichier texte, où les valeurs sont séparées par des virgules dans chaque ligne. Les lignes sont appelées enregistrements de données et chaque enregistrement se compose généralement de plusieurs champs, séparés par des virgules. Le format CSV est principalement utilisé pour stocker des données tabulaires, il contient donc un nombre égal de séparateurs de virgule dans chaque enregistrement. Notez cependant, comme il existe plusieurs implémentations dans la pratique, on peut trouver, par exemple, des espaces entre les champs séparés par des virgules, ou il peut n’y avoir aucun espace entre les champs, etc. Dans l’exemple suivant, nous supposons qu’il n’y a pas d’espaces entre les champs les champs. Ainsi, chaque caractère entre virgules est considéré comme une seule unité de données.

Tout d’abord, nous devons lire le contenu du fichier et le stocker dans un objet std::string. La fonction readFileIntoString utilise std::ostringstream et rdbuf pour lire le fichier et renvoyer la valeur string à la fonction appelante. Une fois l’étape précédente effectuée avec succès, nous pouvons construire un std::istringstream à partir de l’objet string et itérer sur chaque ligne. Dans cette itération, nous mettons une autre boucle pour extraire chaque champ d’une ligne et les stocker dans un std::vector. A la fin de chaque itération de ligne, nous stockons le vector dans le std::map et effaçons le vector pour le cycle suivant. Notez que std::map peut être remplacé par un vecteur de vecteurs ou toute autre structure de données personnalisée qui sera optimale pour le scénario spécifique.

#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
#include <vector>

using std::cerr;
using std::cout;
using std::endl;
using std::ifstream;
using std::istringstream;
using std::ostringstream;
using std::string;

string readFileIntoString(const string& path) {
  auto ss = ostringstream{};
  ifstream input_file(path);
  if (!input_file.is_open()) {
    cerr << "Could not open the file - '" << path << "'" << endl;
    exit(EXIT_FAILURE);
  }
  ss << input_file.rdbuf();
  return ss.str();
}

int main() {
  string filename("grades.csv");
  string file_contents;
  std::map<int, std::vector<string>> csv_contents;
  char delimiter = ',';

  file_contents = readFileIntoString(filename);

  istringstream sstream(file_contents);
  std::vector<string> items;
  string record;

  int counter = 0;
  while (std::getline(sstream, record)) {
    istringstream line(record);
    while (std::getline(line, record, delimiter)) {
      items.push_back(record);
    }

    csv_contents[counter] = items;
    items.clear();
    counter += 1;
  }

  exit(EXIT_SUCCESS);
}

La boucle externe while appelle getline avec un délimiteur par défaut, un caractère de nouvelle ligne, tandis que la boucle interne spécifie une virgule comme troisième argument. Contrairement à l’exemple de code précédent, le suivant implémente la solution pour traiter les espaces de fin dans les champs et analyser les unités de données avant de les stocker dans le vector. Ainsi, nous avons ajouté l’idiome effacer-supprimer à la boucle interne while juste avant que push_back ne soit appelé. Cela traitera tous les caractères d’espaces blancs comme les espaces, les tabulations, les retours chariot, et autres puisque nous utilisons l’objet de fonction isspace comme argument remove_if.

#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
#include <vector>

using std::cerr;
using std::cout;
using std::endl;
using std::ifstream;
using std::istringstream;
using std::ostringstream;
using std::string;

string readFileIntoString(const string& path) {
  auto ss = ostringstream{};
  ifstream input_file(path);
  if (!input_file.is_open()) {
    cerr << "Could not open the file - '" << path << "'" << endl;
    exit(EXIT_FAILURE);
  }
  ss << input_file.rdbuf();
  return ss.str();
}

int main() {
  string filename("grades.csv");
  string file_contents;
  std::map<int, std::vector<string>> csv_contents;
  char delimiter = ',';

  file_contents = readFileIntoString(filename);

  istringstream sstream(file_contents);
  std::vector<string> items;
  string record;

  int counter = 0;
  while (std::getline(sstream, record)) {
    istringstream line(record);
    while (std::getline(line, record, delimiter)) {
      record.erase(std::remove_if(record.begin(), record.end(), isspace),
                   record.end());
      items.push_back(record);
    }

    csv_contents[counter] = items;
    items.clear();
    counter += 1;
  }

  exit(EXIT_SUCCESS);
}
Auteur: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook

Article connexe - C++ File