C++ で CSV ファイルを読む
この記事では、C++ で CSV ファイルを読み取る方法のいくつかの方法について説明します。
C++ で CSV ファイルを読み込むには std::getline
と std::istringstream
を使う
CSV ファイルは一般にテキストファイル形式として知られており、値は各行でコンマで区切られます。行はデータレコードと呼ばれ、各レコードは通常、コンマで区切られた複数のフィールドで構成されます。CSV 形式は主に表形式のデータを格納するために使用されるため、各レコードに同数のコンマ区切り文字が含まれています。ただし、実際には複数の実装があるため、たとえば、コンマで区切られたフィールド間にスペースがある場合や、フィールド間にスペースがない場合などがあります。以下の例では、フィールド間にスペースがないと仮定します。したがって、コンマの間のすべての文字が 1つのデータユニットとみなされます。
まず、ファイルの内容を読み取り、std::string
オブジェクトに保存する必要があります。readFileIntoString
関数は、std::ostringstream
と rdbuf
を使用してファイルを読み取り、string
値を呼び出し元の関数に返します。前の手順が正常に完了したら、string
オブジェクトから std::istringstream
を作成し、各行を反復処理できます。この反復では、別のループを配置して行の各フィールドを抽出し、それらを std::vector
に格納します。すべての行の反復の終わりに、ベクトル
を std::map
に格納し、次のサイクルのためにベクトル
をクリアします。std::map
は、ベクトルのベクトルまたは特定のシナリオに最適なその他のカスタムデータ構造に置き換えることができることに注意してください。
#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);
}
外側の while
ループは、デフォルトの区切り文字である改行文字を使用して getline
を呼び出しますが、内側のループは、3 番目の引数としてコンマ文字を指定します。前のサンプルコードとは対照的に、次のサンプルコードは、フィールドの末尾のスペースを処理し、データユニットを解析してからベクトル
に格納するソリューションを実装します。したがって、push_back
が呼び出される直前に、内側の while
ループに erase-remove
イディオムを追加しました。isspace
関数オブジェクトを 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);
}