CSV-Datei in C++ lesen

Jinku Hu 12 Oktober 2023
CSV-Datei in C++ lesen

In diesem Artikel werden verschiedene Methoden zum Lesen einer CSV-Datei in C++ erläutert.

Verwenden von std::getline und std::istringstream zum Lesen einer CSV-Datei in C++

CSV-Dateien werden allgemein als Textdateiformate bezeichnet, bei denen die Werte in jeder Zeile durch Kommas getrennt sind. Zeilen werden als Datensätze bezeichnet, und jeder Datensatz besteht normalerweise aus mehr als einem durch Kommas getrennten Feld. Das CSV-Format wird hauptsächlich zum Speichern von Tabellendaten verwendet, sodass es in jedem Datensatz die gleiche Anzahl von Komma-Trennzeichen enthält. Da es in der Praxis mehrere Implementierungen gibt, kann es jedoch vorkommen, dass zwischen den durch Kommas getrennten Feldern Leerzeichen oder zwischen den Feldern keine Leerzeichen usw. vorhanden sind. Im folgenden Beispiel wird davon ausgegangen, dass keine Leerzeichen zwischen den Feldern vorhanden sind die Felder. Somit wird jedes Zeichen zwischen Kommas als eine einzelne Dateneinheit betrachtet.

Zuerst müssen wir den Dateiinhalt lesen und in einem std::string-Objekt speichern. Die Funktion readFileIntoString verwendet std::ostringstream und rdbuf, um die Datei zu lesen und den Wert string an die Aufruferfunktion zurückzugeben. Sobald der vorherige Schritt erfolgreich abgeschlossen wurde, können wir aus dem Objekt string einen std::istringstream erstellen und über jede Zeile iterieren. In dieser Iteration setzen wir eine weitere Schleife, um jedes Feld in einer Zeile zu extrahieren und in einem std::vector zu speichern. Am Ende jeder Zeileniteration speichern wir den Vektor in der std::map und löschen den Vektor für den nächsten Zyklus. Beachten Sie, dass std::map durch einen Vektorvektor oder eine andere benutzerdefinierte Datenstruktur ersetzt werden kann, die für das jeweilige Szenario optimal ist.

#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);
}

Die äußere while-Schleife ruft getline mit dem Standardtrennzeichen, einem neuen Zeilenzeichen, auf, während die innere Schleife ein Komma als drittes Argument angibt. Im Gegensatz zum vorherigen Beispielcode implementiert der nächste die Lösung, um nachgestellte Leerzeichen in Feldern zu behandeln und die Dateneinheiten zu analysieren, bevor sie im Vektor gespeichert werden. Daher haben wir das Idiom erase-remove zur inneren while-Schleife hinzugefügt, kurz bevor push_back aufgerufen wird. Dies behandelt alle Leerzeichen wie Leerzeichen, Tabulatoren, Zeilenumbrüche und andere, da wir das Funktionsobjekt isspace als Argument remove_if verwenden.

#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);
}
Autor: 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

Verwandter Artikel - C++ File