【发布时间】:2011-03-19 16:45:04
【问题描述】:
在 C++ 中读取文件的常用方法是这样的:
std::ifstream file("file.txt", std::ios::binary | std::ios::ate);
std::vector<char> data(file.tellg());
file.seekg(0, std::ios::beg);
file.read(data.data(), data.size());
读取 1.6 MB 文件几乎是即时的。
但最近,我发现了std::istream_iterator 并想尝试一下,以便编写一种漂亮的单行方式来读取文件的内容。像这样:
std::vector<char> data(std::istream_iterator<char>(std::ifstream("file.txt", std::ios::binary)), std::istream_iterator<char>());
代码不错,但非常很慢。读取相同的 1.6 MB 文件大约需要 2/3 秒。我知道这可能不是读取文件的最佳方式,但为什么它这么慢?
以经典方式读取文件是这样的(我只是在谈论读取功能):
- istream 包含一个 filebuf,其中包含来自文件的数据块
- read 函数从 filebuf 调用 sgetn,它将字符从内部缓冲区一一复制(无 memcpy)到“数据”的缓冲区
- 当filebuf里面的数据全部读完后,filebuf从文件中读取下一个块
当你使用 istream_iterator 读取文件时,它是这样的:
- 向量调用 *iterator 来获取下一个字符(这只是读取一个变量),将其添加到末尾并增加自己的大小
- 如果向量的分配空间已满(这种情况并不经常发生),则会执行重定位
- 然后它调用 ++iterator 从流中读取下一个字符(操作符 >> 带有 char 参数,它当然只是调用 filebuf 的 sbumpc 函数)
- 最后将迭代器与结束迭代器进行比较,这是通过比较两个指针来完成的
我必须承认,第二种方式效率不高,但至少比第一种方式慢200倍,这怎么可能?
我认为性能杀手是重定位或插入,但我尝试创建一个完整的向量并调用 std::copy,它同样慢。
// also very slow:
std::vector<char> data2(1730608);
std::copy(std::istream_iterator<char>(std::ifstream("file.txt", std::ios::binary)), std::istream_iterator<char>(), data2.begin());
【问题讨论】:
-
“我认为性能杀手是重定位或插入” - 这就是您需要依赖分析的原因。
标签: c++ performance file iterator