用C ++中的行读取一个大文件

时间:2015-08-14 09:29:22

标签: c++ file ifstream

我有一个接近800M的大文件,我想逐行阅读。

起初我用Python编写程序 ,我使用linecache.getline:

lines = linecache.getlines(fname)

成本约为1.2秒。

现在我想将我的程序移植到C ++。

我写了这些代码:

    std::ifstream DATA(fname);
    std::string line;
    vector<string> lines;

    while (std::getline(DATA, line)){
        lines.push_back(line);
    }

但它很慢(成本分钟)。如何改进?

  • Joachim Pileborg提及mmap(),并且在CreateFileMapping()窗口上工作。

我的代码在VS2013下运行,当我使用“DEBUG”模式时,需要162秒;

当我使用“RELEASE”模式时,只有7秒!

非常感谢@DietmarKühl和@Andrew

2 个答案:

答案 0 :(得分:1)

对于c ++,您可以尝试这样的事情:

void processData(string str)
{
  vector<string> arr;
  boost::split(arr, str, boost::is_any_of(" \n"));
  do_some_operation(arr);
}

int main()
{
 unsigned long long int read_bytes = 45 * 1024 *1024;
 const char* fname = "input.txt";
 ifstream fin(fname, ios::in);
 char* memblock;

 while(!fin.eof())
 {
    memblock = new char[read_bytes];
    fin.read(memblock, read_bytes);
    string str(memblock);
    processData(str);
    delete [] memblock;
 }
 return 0;
}

答案 1 :(得分:1)

首先,您应该确保在编译时启用了优化。这对于这样一个简单的算法可能无关紧要,但这实际上取决于你的向量/字符串库实现。

正如@angew所建议的那样,std::ios_base::sync_with_stdio(false)对你所写的例程有很大的影响。

另一个较小的优化是使用lines.reserve()预分配您的向量,以便push_back()不会导致大量的复制操作。但是,如果您事先知道可能会收到多少行,这将非常有用。

使用上面建议的优化,我获得了以下读取800MB文本流的结果:

 20 seconds ## if average line length = 10 characters
  3 seconds ## if average line length = 100 characters
  1 second  ## if average line length = 1000 characters

正如您所看到的,速度主要受每行开销的影响。此开销主要发生在std::string类中。

基于存储大量std::string的任何方法很可能在内存分配开销方面不是最理想的。在64位系统上,std::string将需要每个字符串16字节开销的最小。实际上,开销很可能远远大于开销 - 你可能会发现内存分配(std::string内部)成为一个重要的瓶颈。

为了获得最佳的内存使用和性能,请考虑编写自己的例程,以大块方式读取文件,而不是使用getline()。然后,您可以应用类似于flyweight pattern的内容来管理使用自定义字符串类对各行进行索引。

P.S。另一个相关因素是物理磁盘I / O,它可能会或可能不会被缓存绕过。