在 C++ 中讀取 CSV 檔案

Jinku Hu 2021年4月29日
在 C++ 中讀取 CSV 檔案

本文將說明幾種如何在 C++ 中讀取 CSV 檔案的方法。

使用 std::getlinestd::istringstream 讀取 C++ 中的 CSV 檔案

CSV 檔案通常稱為文字檔案格式,其中的值在每行中用逗號分隔。行稱為資料記錄,每條記錄通常包含多個欄位,以逗號分隔。CSV 格式主要用於儲存表格資料,因此每個記錄中包含相等數量的逗號分隔符。但是請注意,由於實際上有多種實現,因此可能會發現例如以逗號分隔的欄位之間有空格,或者欄位之間可能沒有空格等。在以下示例中,我們假定之間沒有空格田野。因此,逗號之間的每個字元都被視為一個資料單元。

首先,我們需要讀取檔案內容並將其儲存在 std::string 物件中。readFileIntoString 函式利用 std::ostringstreamrdbuf 讀取檔案,並將 string 值返回給呼叫方函式。一旦上一步成功完成,我們就可以從字串物件構造一個 std::istringstream,並在每行上進行迭代。在此迭代中,我們放置了另一個迴圈以提取一行中的每個欄位,並將它們儲存在 std::vector 中。在每行迭代結束時,我們將 vector 儲存在 std::map 中,並清除 vector 進行下一個迴圈。請注意,std::map 可以替換為向量的向量或對特定情況最佳的任何其他自定義資料結構。

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

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

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,而內部的迴圈將逗號字元指定為第三個引數。與前面的示例程式碼相反,下一個示例程式碼實現了一種解決方案,以處理欄位中的尾隨空格並解析資料單元,然後再將其儲存在向量中。因此,在呼叫 push_back 之前,我們在內部的 while 迴圈中新增了 erase-remove 習慣用法。因為我們將 isspace 函式物件用作 remove_if 引數,所以它將處理任何空格字元,例如空格、製表符、回車符和其他字元。

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

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

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

相關文章 - C++ File