作为 C++ 迭代器抽象和算法的忠实拥护者,我希望以下方法能够快速将文件(或任何其他输入流)读入 std::string(然后打印内容):
#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
int main()
{
std::string s(std::istreambuf_iterator<char>(std::ifstream("file")
>> std::skipws),
std::istreambuf_iterator<char>());
std::cout << "file='" << s << "'\n";
}
这对于我自己的 IOStreams 实现来说确实很快,但实际上要快速实现它需要很多技巧。首先,它需要优化算法来处理分段序列:一个流可以看作是一个输入缓冲区序列。我不知道有任何 STL 实现一直在做这种优化。 std::skipws 的奇怪用法只是获取对刚刚创建的流的引用:std::istreambuf_iterator<char> 期望临时文件流不会绑定到的引用。
由于这可能不是最快的方法,我倾向于使用带有特定“换行符”字符的std::getline(),即文件中没有的字符:
std::string s;
// optionally reserve space although I wouldn't be too fuzzed about the
// reallocations because the reads probably dominate the performances
std::getline(std::ifstream("file") >> std::skipws, s, 0);
这假定文件不包含空字符。任何其他角色也可以。不幸的是,std::getline() 将 char_type 用作分隔参数,而不是 int_type 成员 std::istream::getline() 用作分隔符:在这种情况下,您可以将 eof() 用于从未出现的字符(@ 987654332@、int_type、eof()分别指char_traits<char>的成员)。反过来,会员版本不能使用,因为您需要提前知道文件中有多少个字符。
顺便说一句,我看到一些尝试使用 seek 来确定文件的大小。这注定不会很好地工作。问题是在std::ifstream(好吧,实际上是在std::filebuf)中完成的代码转换可以创建与文件中的字节数不同的字符数。诚然,在使用默认 C 语言环境时情况并非如此,并且可以检测到这不会进行任何转换。否则,流的最佳选择是遍历文件并确定正在生成的字符数。我实际上认为这是当代码转换可能会发生一些有趣的事情时需要做的,尽管我认为它实际上并没有完成。但是,没有一个示例明确设置 C 语言环境,例如使用std::locale::global(std::locale("C"));。即使这样,也需要以std::ios_base::binary 模式打开文件,否则读取时行尾序列可能会被单个字符替换。诚然,这只会使结果更短,永远不会更长。
使用从std::streambuf* 提取的其他方法(即涉及rdbuf() 的方法)都要求在某个时间点复制生成的内容。鉴于文件实际上可能非常大,这可能不是一个选项。然而,如果没有副本,这很可能是最快的方法。为避免复制,可以创建一个简单的自定义流缓冲区,它将对 std::string 的引用作为构造函数参数并直接附加到此 std::string:
#include <fstream>
#include <iostream>
#include <string>
class custombuf:
public std::streambuf
{
public:
custombuf(std::string& target): target_(target) {
this->setp(this->buffer_, this->buffer_ + bufsize - 1);
}
private:
std::string& target_;
enum { bufsize = 8192 };
char buffer_[bufsize];
int overflow(int c) {
if (!traits_type::eq_int_type(c, traits_type::eof()))
{
*this->pptr() = traits_type::to_char_type(c);
this->pbump(1);
}
this->target_.append(this->pbase(), this->pptr() - this->pbase());
this->setp(this->buffer_, this->buffer_ + bufsize - 1);
return traits_type::not_eof(c);
}
int sync() { this->overflow(traits_type::eof()); return 0; }
};
int main()
{
std::string s;
custombuf sbuf(s);
if (std::ostream(&sbuf)
<< std::ifstream("readfile.cpp").rdbuf()
<< std::flush) {
std::cout << "file='" << s << "'\n";
}
else {
std::cout << "failed to read file\n";
}
}
At least with a suitably chosen buffer I would expect the version to be the fairly fast.哪个版本最快肯定取决于系统、正在使用的标准 C++ 库,以及可能还有许多其他因素,即您想要衡量性能。