在C ++中读取包含大量列和行的csv文件的最快方法

时间:2019-07-17 09:11:17

标签: c++ string performance optimization vector

我有一个用管道分隔的数据文件,其中包含13列以上。文件总大小超过100 MB。我正在读取每一行,将字符串拆分为std::vector<std::string>,以便可以进行计算。我对文件中的所有行重复此过程,如下所示:

    string filename = "file.dat";
    fstream infile(filename);
    string line;
    while (getline(infile, line)) {
        string item;
        stringstream ss(line);
        vector<string> splittedString;
        while (getline(ss, item, '|')) {
            splittedString.push_back(item);
        }
        int a = stoi(splittedString[0]); 
        // I do some processing like this before some manipulation and calculations with the data
    }

但是,这非常耗时,我很确定这不是读取CSV类型文件的最优化方法。如何改善呢?

更新

我尝试使用boost::split函数而不是while循环,但实际上它甚至更慢。

2 个答案:

答案 0 :(得分:4)

您没有CSV文件,因为CSV代表逗号分隔的值,而您没有。
您有一个分隔的文本文件(显然由"|"分隔)。解析CSV比仅在","上拆分要复杂得多。

无论如何,如果您的方法没有太大的戏剧性变化,这里有一些建议:

  • 使用(更多)缓冲
  • vector移出循环,并在每次迭代中clear()移出。这样可以节省堆的重新分配。
  • 使用string::find()而不是stringstream来分割字符串。

像这样...

using namespace std;
int main() {
    string filename = "file.dat";
    fstream infile(filename);
    char buffer[65536];
    infile.rdbuf()->pubsetbuf(buffer, sizeof(buffer));
    string line;
    vector<string> splittedString;
    while (getline(infile, line)) {
        splittedString.clear();
        size_t last = 0, pos = 0;
        while ((pos = line.find('|', last)) != std::string::npos) {
            splittedString.emplace_back(line, last, pos - last);
            last = pos + 1;
        }
        if (last)
            splittedString.emplace_back(line, last);
        int a = stoi(splittedString[0]);
        // I do some processing like this before some manipulation and calculations with the data
    }
}

答案 1 :(得分:1)

通过消除“ vector splittedString;”,您可以节省另外的50%;并使用strtok_s()就地解析

int main() {
auto t1 = high_resolution_clock::now();
long long a(0);

string filename = "file.txt";
fstream infile(filename);
char buffer[65536];
infile.rdbuf()->pubsetbuf(buffer, sizeof(buffer));
string line;
while (getline(infile, line)) {

    char * pch = const_cast<char*>(line.data());
    char *nextToken = NULL;
    pch = strtok_s(pch, "|", &nextToken);
    while (pch != NULL)
    {
        a += std::stoi(pch);
        pch = strtok_s(NULL, "|", &nextToken);
    }
}

auto t2 = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(t2 - t1).count();
std::cout << duration << "\n";
std::cout << a << "\n";

}