我知道这将是一个非常愚蠢的问题,但在阅读了很多关于整个“缓冲”系统的文档后,我无法理解为什么人们会刷新流而不是缓冲区。
我见过人们写这样的东西:
FILE* file=fopen("mytext.txt","wr");
char buffer[10]="";
setbuf(file,buffer);
//do some stuff....
fflush(file);
....
fclose(file);
所以我想知道,因为我们实际上将事物存储在缓冲区中,为什么我们要刷新与之关联的流而不是直接刷新缓冲区,实际存储了一些东西,应该刷新。(好吧,有些人告诉我,如果事情像我说的那样,那将是同样的事情,所以打扰自己......)
例如,我们不能写fflush(buffer)
之类的内容。为什么?
答案 0 :(得分:6)
刷新将数据从流的内部缓冲区复制到基础文件。
因此,刷新功能需要知道要复制的源和目的地。
这取决于I / O实现,对于C ++ <iostream>
,请参阅Jerry Coffin的回答 - <iostream>
中的缓冲区更加智能。
使用C风格的<cstdio>
,如果你只想用一个参数刷新,FILE*
或者char数组需要知道它应该复制到的文件。
你的缓冲区是一个哑数组,它只存储读/写数据。由于那里没有其他信息,获取指向缓冲区的指针的函数无法知道目标的写入位置 - 因此假想的fflush
调用看起来像fflush(buffer, file);
并且没有&# 39; t让你到任何地方。另一方面,FILE*
存储指向缓冲区的指针(使用setbuf(file,buffer)
函数调用设置指针)。
答案 1 :(得分:2)
以下仅涉及iostream及其缓冲对象。有关与C风格I / O相关的缓冲区的信息,请参阅@ milleniumbug的答案。
主要是因为如果尝试刷新底层缓冲区失败,你(至少通常)需要流的badbit集。
还有一个稍微复杂的小舞蹈,在与底层流交互时流使用,其中流创建一个哨兵对象,然后执行一个动作,然后哨兵对象被摧毁。哨兵旨在使前缀和后缀操作异常安全。
所以总体顺序是这样的:
create sentry
if that succeeds (sentry converts to true) call rdbuf()->pubsync()
if that fails (returns -1) setstate(badbit);
流缓冲区(例如,basic_filebuf
)直接附加到底层文件系统对象 - 实际上,iostream对象和底层文件对象之间的所有交互都是通过>完成的> em>文件缓冲区。如上所示,当流对象确实需要刷新缓冲区时,它需要做的只是通过调用缓冲区的pubsync()
成员函数来告诉缓冲区刷新自己。
[供参考:[ostream.unformatted] / 7:
basic_ostream&安培;冲洗();
效果:表现为无格式输出函数(如27.7.3.6.1第1段所述)。如果rdbuf()不是空指针,则构造一个sentry对象。如果此对象在转换为bool类型的值时返回true,则函数调用rdbuf() - &gt; pubsync()。如果该函数返回-1,则调用setstate(badbit)(可能会抛出ios_base :: failure(27.5.5.4))。否则,如果sentry对象返回false,则不执行任何操作。
返回:* this。
...和[ofstream.cons] / 2:
显式basic_ofstream(const char * s, ios_base :: openmode mode = ios_base :: out);
效果:构造一个basic_ofstream类的对象,用basic_ostream(&amp; sb)初始化基类并用basic_filebuf()初始化sb(27.7.3.2,27.9.1.2),然后调用rdbuf() - &gt; open (s,mode | ios_base :: out)。如果该函数返回空指针,则调用setstate(failbit)。
答案 2 :(得分:0)
我无法理解为什么人们会刷新流而不是缓冲区。
因为缓冲区不知道应该将其刷新到何处。流确实。
FILE* file=fopen("mytext.txt","wr"); setbuf(file,buffer);
默认情况下,FILE
结构包含指向其自己的内部缓冲区的指针。 setbuf()
将该缓冲区替换为调用者提供的缓冲区。但无论哪种方式,fwrite()
,fput...()
和其他类似函数都将数据写入流的当前缓冲区,fflush()
将该缓冲区的内容刷新到基础文件。
BTW,setbuf()
要求调用者提供的缓冲区大小至少为BUFSIZ
:
char buffer[BUFSIZ]="";
所以我想知道,因为我们实际上将事物存储在缓冲区中,为什么我们要刷新与之关联的流而不是直接刷新缓冲区,这实际上存储了一些东西并且应该刷新。
因为缓冲区只是数据存储。它不知道如何使用数据。流知道它的缓冲区用于什么(缓存写入数据),以及需要刷新到哪里(关联文件)。所以你必须刷新流,以便它可以利用这些信息。
例如,我们不能写像fflush(缓冲区)这样的东西。为什么呢?
您希望缓冲区将其内容刷新到哪里?它没有这样的信息。