5

我知道这将是一个非常愚蠢的问题,但是在阅读了这么多关于整个“缓冲区”系统的文档之后,我不明白为什么人们会刷新流而不是缓冲区。

我见过有人这样写:

FILE* file=fopen("mytext.txt","wr");
char buffer[10]="";
setbuf(file,buffer);

//do some stuff....

fflush(file);
....
fclose(file);

所以我想知道,既然我们实际上将东西存储在缓冲区中,为什么我们刷新它关联的流而不是直接刷新缓冲区,它实际上存储了一些东西并且应该被刷新。(好吧,有些人告诉我,如果事情发生了就像我说的那样,这将是同样的事情,所以麻烦自己......)

例如,我们不能写fflush(buffer).Why?

4

3 回答 3

6

刷新将数据从流的内部缓冲区复制到底层文件。

所以刷新函数需要知道复制的源和目标。

这取决于 I/O 实现,对于 C++,<iostream>请参阅 Jerry Coffin 的答案 - 中的缓冲区<iostream>更智能。

使用 C-style <cstdio>,如果您只想使用一个参数刷新,FILE*或者 char 数组需要知道它应该复制到的文件。

您的缓冲区是一个哑数组,它只存储用于读/写的数据。由于那里没有其他信息,因此获取指向缓​​冲区的指针的函数无法知道将其写入的目标 - 所以想象中的fflush调用看起来fflush(buffer, file);不会让你到任何地方。另一方面,FILE*存储指向缓冲区的指针(您使用setbuf(file,buffer)函数调用设置指针)。

于 2015-05-29T23:06:24.793 回答
2

以下仅涉及 iostream 及其缓冲区对象。有关与 C 样式 I/O 相关的缓冲区的信息,请参阅@milleniumbug 的答案。

主要是因为如果尝试刷新底层缓冲区失败,您(至少通常)希望设置流的坏位。

当流与底层流交互时,流使用的还有一个稍微复杂的小舞蹈,其中流创建一个哨兵对象,然后执行一个动作,然后哨兵对象被销毁。sentry 旨在使前缀和后缀操作异常安全。

所以整体顺序是这样的:

create sentry
if that succeeds (sentry converts to true) call rdbuf()->pubsync()
    if that fails (returns -1) setstate(badbit);

流缓冲区(例如 a basic_filebuf)直接附加到底层文件系统对象——事实上,iostream 对象和底层文件对象之间的所有交互都是通过文件缓冲区完成的。如上所示,当流对象确实需要刷新缓冲区时,它所要做的就是通过调用缓冲区的pubsync()成员函数来告诉缓冲区刷新自己。

[供参考:[ostream.unformatted]/7:

basic_ostream&flush();

效果:表现为未格式化的输出函数(如 27.7.3.6.1 第 1 段所述)。如果 rdbuf() 不是空指针,则构造一个哨兵对象。如果此对象在转换为 bool 类型的值时返回 true,则函数调用 rdbuf()->pubsync()。如果该函数返回 -1 调用 setstate(badbit) (可能会抛出 ios_base::failure (27.5.5.4))。否则,如果哨兵对象返回 false,则不执行任何操作。

返回:*this。

...和 ​​[ofstream.cons]/2:

显式 basic_ofstream(const char* s, ios_base::openmode mode = ios_base::out);

作用:构造类basic_ofstream的对象,用basic_ostream(&sb)初始化基类,用basic_filebuf())(27.7.3.2, 27.9.1.2)初始化sb,然后调用rdbuf()->open(s, mode|ios_base ::出去)。如果该函数返回空指针,则调用 setstate(failbit)。

于 2015-05-29T23:46:04.520 回答
0

我不明白为什么人们会刷新流而不是缓冲区。

因为缓冲区不知道它应该被刷新到哪里。流可以。

FILE* file=fopen("mytext.txt","wr");
setbuf(file,buffer);

默认情况下,一个FILE结构包含一个指向它自己的内部缓冲区的指针。 setbuf()用调用者提供的缓冲区替换该缓冲区。但无论哪种方式,fwrite()fput...()其他类似函数都将数据写入流的当前缓冲区,并将fflush()该缓冲区的内容刷新到底层文件。

顺便说一句,setbuf()要求调用者提供的缓冲区至少BUFSIZ大小:

char buffer[BUFSIZ]="";

所以我想知道,既然我们实际上将东西存储在缓冲区中,为什么我们要刷新它关联的流而不是直接刷新缓冲区,因为缓冲区实际上存储了一些东西并且应该被刷新。

因为缓冲区只是数据存储。它对数据的使用方式一无所知。流知道它的缓冲区正在用于什么(缓存写入的数据),以及它需要刷新到哪里(关联文件)。因此,您必须刷新流,以便它可以利用该信息。

例如,我们不能写 fflush(buffer) 之类的东西。为什么?

您希望缓冲区将其内容刷新到哪里?它没有这样的信息。

于 2015-05-30T01:09:45.747 回答