这个流命令如何在 C++ 中读取整个文件?

How does this one stream command read in an entire file in c++?

鉴于此:

auto f = std::ifstream{file};
if (f) {
    std::stringstream stream;
    stream << f.rdbuf();
    return stream.str();
}
return std::string{};

我不明白为什么会这样。 我不知道 f 是什么类型,因为它说自动,但显然你可以检查它是否为非零。 但是当文件很大时,比如 2 gig,运行 中的延迟发生在 这一行:

    stream << f.rdbuf();

文档说 rdbuf() 为您提供指向 ifstream 内部缓冲区的指针。因此,为了让它读取整个文件,缓冲区必须调整文件大小,并一次加载所有文件。但是当流 << 发生时,rdbuf() 必须已经设置,否则它将无法 return 一个点。 我希望构造函数在这种情况下这样做,但它显然是延迟加载的,因为在构造时读取整个文件对于其他所有用例都是不利的,并且延迟在流 << 命令中。

有什么想法吗?所有其他关于将文件读入字符串的堆栈溢出引用总是以某种方式循环。

如果涉及到一些缓冲区,显然有,它能有多大?如果是1字节怎么办,肯定会很慢。

可爱的 c++ 非常不透明,对于必须知道幕后发生的事情的程序员来说是不利的。

先回答你的第一个问题:

f 是分配给它的类型,std::ifstream,但这是一种相当愚蠢的写法。人们通常会写 std::ifstream f {...}。一个流有一个重载的 operator bool () 给你 !fail().

关于第二个问题:什么.rdbuf()returns是一个streambuf对象。该对象在返回时不包含整个文件内容。相反,它提供了一个访问数据的接口,这个接口被 stringstream stream.

使用

当参数是 streambuf 时,它是如何在 ostream 上定义 operator<< 的函数。只要 streambuf 不是空指针,它就会从 streambuf 控制的输入序列中提取字符并将它们插入到 *this 中,直到满足以下条件之一(请参阅operator<< overload note #9):

  • end-of-file occurs on the input sequence;
  • inserting in the output sequence fails (in which case the character to be inserted is not extracted);
  • an exception occurs (in which case the exception is caught).

基本上,ostreamstringstream 继承自)知道如何使用 streambuf 从与其关联的文件中提取所有数据。这是一种惯用的方式,但正如您所注意到的,不是直观的方式来吞噬整个文件。 streambuf 实际上并没有缓冲这里的所有数据(正如你所注意到的,在一般情况下将整个文件读入缓冲区是不好的),只是它有必要的连接来调整缓冲的 window 因为 ostream 要求更多(越来越多)数据。

if (f) 之所以有效,是因为 ifstream 具有 an overload for operator bool,它在测试 ifstream 的 "truthiness" 时隐式调用,告诉您文件是否处于失败状态。

auto f = std::ifstream{file};

f 的类型是 std::ifstream

stream << f.rdbuf();

std::ifstream 维护一个缓冲区,您可以通过 f.rdbuf() 获得它,它不会一次加载整个文件。当调用上述命令时加载发生,stringstream 将从该缓冲区中提取数据,并且 ifstream 将在缓冲区用完数据时执行加载。

您可以使用 setbuf.

手动设置缓冲区大小