【问题标题】:Parse files the fast way?快速解析文件?
【发布时间】:2012-03-09 00:34:41
【问题描述】:

我正在编写一个应该读取最常见图形格式的图形库。一种格式包含如下信息:

e 4 3
e 2 2
e 6 2
e 3 2
e 1 2
....

我想解析这些行。我在 stackoverflow 上环顾四周,可以找到 neat solution 来执行此操作。我目前使用这样的方法(文件是 fstream):

string line;
while(getline(file, line)) {
    if(!line.length()) continue; //skip empty lines
    stringstream parseline = stringstream(line);
    char identifier;
    parseline >> identifier; //Lese das erste zeichen
    if(identifier == 'e')   {
        int n, m;
        parseline >> n;
        parseline >> m;
        foo(n,m) //Here i handle the input
    }
}

它工作得非常好并且符合预期,但是今天当我用巨大的图形文件(50 mb+)测试它时,我震惊地发现这个函数是整个程序中迄今为止最严重的瓶颈:

我用来解析行的字符串流使用了几乎 70% 的总运行时间和 25% 的 getline 命令。程序的其余部分仅使用 5%。

有没有一种快速读取这些大文件的方法,可能避免缓慢的字符串流和 getline 函数?

【问题讨论】:

  • 你考虑过 boost::spirit 吗?
  • 如果可能的话,我想避免提升。
  • 美元到甜甜圈,您的 C 库 scanf 可以击败所有这些。 :)

标签: c++ file optimization fstream


【解决方案1】:

您可以跳过双缓冲字符串,跳过解析单个字符,并使用strtoll 解析整数,如下所示:

string line;
while(getline(file, line)) {
    if(!line.length()) continue; //skip empty lines
    if (line[0] == 'e') {
        char *ptr;
        int n = strtoll(line.c_str()+2, &ptr, 10);
        int m = strtoll(ptr+1, &ptr, 10);
        foo(n,m) //Here i handle the input
    }
}

在 C++ 中,strtoll 应该在 <cstdlib> 包含文件中。

【讨论】:

  • 很好,我认为结合这两个答案我可以写出非常快的东西。
【解决方案2】:

mmap 文件并将其作为单个大缓冲区处理。

如果您的系统缺少 mmap,您可以尝试将 read 文件放入您 malloc 的缓冲区中

基本原理:大部分时间是在从用户到系统的转换以及对 C 库的调用中。读入整个文件几乎可以消除所有这些调用。

【讨论】:

  • 谢谢,我会试试这个并报告我的结果。然而,一个主要的瓶颈是通过字符串流进行解析,仅仅读取巨大缓冲区中的所有内容是无法消除的。
猜你喜欢
  • 1970-01-01
  • 2018-12-09
  • 2017-09-13
  • 2010-12-27
  • 1970-01-01
  • 2014-10-14
  • 2018-07-08
  • 2011-10-14
  • 1970-01-01
相关资源
最近更新 更多