【发布时间】:2015-06-27 19:36:08
【问题描述】:
事实上,有很多方法可以将文件读入字符串。 两个常见的方法是使用 ifstream::read 直接读取字符串并使用 steambuf_iterators 和 std::copy_n:
使用 ifstream::read:
std::ifstream in {"./filename.txt"};
std::string contents;
in.seekg(0, in.end);
contents.resize(in.tellg());
in.seekg(0, in.beg);
in.read(&contents[0], contents.size());
使用 std::copy_n:
std::ifstream in {"./filename.txt"};
std::string contents;
in.seekg(0, in.end);
contents.resize(in.tellg());
in.seekg(0, in.beg);
std::copy_n(std::streambuf_iterator<char>(in),
contents.size(),
contents.begin();
许多基准测试表明,第一种方法比第二种方法快得多(在我使用 g++-4.9 的机器上,使用 -O2 和 -O3 标志的速度大约快 10 倍),我想知道这可能是什么原因这种性能差异。
【问题讨论】:
-
我怀疑迭代器一次读取一个字符。这可以解释差异。
-
@RSahu:更具体地说,迭代器对每个字节使用 1+ 次虚拟调用,而
read是每个缓冲区 1-2 次虚拟调用。 -
旁注:你也可以像
std::string contents(std::streambuf_iterator<char>(in), {});这样就地构造字符串,不需要copy_n和获取文件的大小。但在速度方面可能不会有很大的不同。 -
@RSahu 确实不应该,那将是一个糟糕的实现。事实上,我想我记得 libstdc++ 实现对文件缓冲区迭代器非常聪明,甚至预先确定了缓冲区的大小(这需要确定缓冲区迭代器指向一个可查找的文件)。不过我可能记错了。
-
我们所说的文件有多大?这可能取决于此。此外,您可能需要小心地将整个内容以一大块的形式读入内存,而不知道它可能有多大。根据您正在执行的处理类型,该程序一次读取一行可能会更有效。
标签: c++ performance optimization io iterator