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