【发布时间】:2015-11-17 03:31:21
【问题描述】:
许多其他帖子,如“Read whole ASCII file into C++ std::string”解释了一些选项是什么,但没有深入描述各种方法的优缺点。我想知道为什么一种方法比另一种更可取?
所有这些都使用std::fstream 将文件读入std::string。我不确定每种方法的成本和收益。让我们假设这是针对已知读取文件具有一些可以轻松容纳的小内存的常见情况,显然无论您如何将多 TB 文件读入内存都是一个坏主意。
在几次谷歌搜索后,将整个文件读入 std::string 的最常见方法是使用 std::getline 并在每行之后附加一个换行符。这对我来说似乎没有必要,但是否有一些性能或兼容性原因表明这是理想的?
std::string Results;
std::ifstream ResultReader("file.txt");
while(ResultReader)
{
std::getline(ResultReader, Results);
Results.push_back('\n');
}
我拼凑的另一种方法是更改 getline 分隔符,使其不在文件中。 EOF 字符似乎不太可能位于文件中间,因此这似乎是一个可能的候选者。这包括强制转换,因此至少有一个不这样做的理由,但这确实会立即读取一个文件而没有字符串连接。据推测,分隔符检查仍有一些成本。是否还有其他充分的理由不这样做?
std::string Results;
std::ifstream ResultReader("file.txt");
std::getline(ResultReader, Results, (char)std::char_traits<char>::eof());
强制转换意味着在将 std::char_traits::eof() 定义为非 -1 的系统上可能会出现问题。与使用std::getline 和string::push_pack('\n') 的其他方法相比,这是不选择此方法的实际原因吗?
这些与其他一次读取文件的方式相比如何,例如这个问题:Read whole ASCII file into C++ std::string
std::ifstream ResultReader("file.txt");
std::string Results((std::istreambuf_iterator<char>(ResultReader)),
std::istreambuf_iterator<char>());
这似乎是最好的。它将几乎所有的工作卸载到标准库上,标准库应该针对给定的平台进行大量优化。除了流有效性和文件结尾之外,我认为没有其他检查的理由。这是理想的还是存在看不见的问题。
某些实现的标准或细节是否提供了偏好某种方法而不是另一种方法的理由?我是否错过了一些在各种情况下可能证明是理想的方法?
将整个文件读入std::string 的最简单、最惯用、性能最佳且符合标准的方法是什么?
编辑 - 2 这个问题促使我编写了一小套基准测试。它们是 MIT 许可证,可在 github 上获取:https://github.com/Sqeaky/CppFileToStringExperiments
Fastest - TellSeekRead 和 CtellSeekRead- 系统提供了一个简单的获取大小并一次读取文件的方法。
更快 - Getline Appending 和 Eof - 字符检查似乎不会产生任何成本。
Fast - RdbufMove 和 Rdbuf - std::move 似乎对发布没有影响。
慢 - 迭代器、BackInsertIterator 和 AssignIterator - 迭代器和输入流有问题。记忆中的工作很棒,但不是在这里。也就是说,其中一些比其他更快。
到目前为止,我已经添加了所有建议的方法,包括链接中的方法。如果有人可以在 Windows 和其他编译器上运行它,我将不胜感激。我目前无法访问具有 NTFS 的机器,并且已经注意到这一点和编译器细节可能很重要。
至于衡量简单性和惯用性,我们如何客观地衡量这些?简单似乎是可行的,也许使用一些线 LOCs 和 Cyclomatic 复杂性,但某些东西是多么地道似乎纯粹是主观的。
【问题讨论】:
-
链接的答案使用 seek/tell 来查找文件的长度。如果你知道它是一个常规文件,使用 stat 会更简单。
-
stat符合标准,但标准是 POSIX。 -
我所怀疑的。我正在限定斯塔克的评论。
-
我应该@replied 给你们两个,我不是要挑剔任何人。即便如此,
stat对许多人来说也是一个可行的答案。