为什么我们刷新流而不是缓冲区?

时间:2015-05-29 22:55:25

标签: c++ c buffer fflush

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

我见过人们写这样的东西:

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

//do some stuff....

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

所以我想知道,因为我们实际上将事物存储在缓冲区中,为什么我们要刷新与之关联的流而不是直接刷新缓冲区,实际存储了一些东西,应该刷新。(好吧,有些人告诉我,如果事情像我说的那样,那将是同样的事情,所以打扰自己......)

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

3 个答案:

答案 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(缓冲区)这样的东西。为什么呢?

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