How to Read CSV File in C++

Jinku Hu Feb 02, 2024
How to Read CSV File in C++

This article will explain several methods of how to read a CSV file in C++.

Use std::getline and std::istringstream to Read CSV File in C++

CSV file is commonly known as text file format, where values are separated by commas in each line. Lines are called data records, and each record usually consists of more than one field, separated by commas. CSV format is mostly used to store tabular data, so it contains an equal number of comma delimiters in each record. Note though, since there are multiple implementations in practice, one might find, e.g., spaces between the comma-separated fields, or there might be no spaces between the fields, etc. In the following example, we assume that there are no spaces between the fields. Thus every character between commas is considered a single data unit.

First, we need to read the file contents and store them in a std::string object. readFileIntoString function utilizes std::ostringstream and rdbuf to read the file and return string value to the caller function. Once the previous step is done successfully, we can construct a std::istringstream from the string object and iterate over each line. In this iteration, we put another loop to extract each field in a line and store them into a std::vector. At the end of every line iteration, we store the vector in the std::map and clear the vector for the next cycle. Note that std::map can be substituted with a vector of vectors or any other custom data structure that will be optimal for the specific scenario.

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

The outer while loop calls getline with default delimiter, a new line character, whereas the inner loop specifies a comma character as a third argument. In contrast with the previous sample code, the next one implements the solution to deal with trailing spaces in fields and parse the data units before storing them in the vector. Thus, we added the erase-remove idiom to the inner while loop just before push_back is called. This will deal with any whitespaces characters like spaces, tabs, carriage returns, and others since we use the isspace function object as the remove_if argument.

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

Related Article - C++ File