From : https://www.gnu.org/software/libc/manual/html_node/Stream-Buffering.html
译者:李秋豪html
一般状况下,写入流的字符会在写入前进行累积而后以块的形式异步转送而非由应用程序立刻输出。类似的,流一般从主机环境以块的形式而非字节-字节的形式读入数据。这称为缓冲。node
若是你正在写一个用流来交互的程序,当你设计交互接口时你须要理解缓冲是如何工做的。不然,你可能会发现输出(例如进程提示信息)不输出理想值,或者出现奇怪的行为。数组
这一节讲解的是在流/文件/设备之间传输设备,并不会涉及echoing, flow control, 特殊设备。若是想了解关于终端设备的通用控制操做符的信息,参考Low-Level Terminal Interface。异步
你能够经过使用底层I/O函数与文件描述符来来避免使用流缓冲。参考 Low-Level I/O。ide
一共有三种缓冲策略:(译者注:缓冲策略是写入流/文件的充分条件,不是必要的。缓冲区存在的意义就是在使用“Stream-level I/O”时从缓冲区进行异步块写入/读出,这样能够在设备堵塞的时候或者有大量的写操做时加快效率。若是一次只写入少许数据,内核一看没有堵塞,“干脆”就把缓冲区的内容写入了,反正放着也是放着)函数
新开的流通常是满缓冲的,只有一个例外:当流是一个可交互设备(例如终端)的时候,流将变为行缓冲。若是想了解关于如何选择缓冲策略,参考 Controlling Buffering 。一般状况下,默认会选择出最方便的缓冲策略。ui
在行缓冲下,以换行符结束的信息会立刻输出到交互设备里——这一般是你想要的。不以换行符结尾的信息可能不会立刻显示到交互设备,因此若是你想要当即显示,你须要在写入后使用fflush
, 参考 Flushing Buffers.(译者注:一般使用fprintf+stderr,由于stderr默认是无缓冲的)this
清除缓冲区意味着当即以块的形式写入缓冲区内收集的内容。有不少状况下缓冲区会自动清除:操作系统
exit
结束的时候。参考 Normal Termination。If you want to flush the buffered output at another time, call fflush
, which is declared in the header file stdio.h.若是你想要在别的时候清除缓冲区,可使用stdio.h中声明的fflush
。翻译
Function: int fflush (FILE *stream)
Preliminary: | MT-Safe | AS-Unsafe corrupt | AC-Unsafe lock corrupt | See POSIX Safety Concepts.这个函数会致使与stream关联的缓冲区被写入到文件中,若是stream是一个空指针,那么fflush
会致使目前打开的全部流的缓冲区被清除。这个函数将返回EOF
若是发生一个写入错误,不然返回0。
Function: int fflush_unlocked (FILE *stream)
Preliminary: | MT-Safe race:stream | AS-Unsafe corrupt | AC-Unsafe corrupt | See POSIX Safety Concepts. fflush_unlocked
函数和fflush
相同,除了它不会隐式的阻塞(block)这个stream流。
此处省略一些...
Function: void **_flushlbf** (void)
Preliminary: | MT-Safe | AS-Unsafe corrupt | AC-Unsafe lock corrupt | See POSIX Safety Concepts.该函数会清除全部的行缓冲流的缓冲区,声明在stdio_ext.h头文件中。
兼容性: 有一些脑子坏掉的操做系统老是对那些以换行符为导向的输入“念念不忘”——清除一个行缓冲会致使一个换行符被写入。幸运的是,这个特性愈来愈少见,而且对于GNU C Library 你不用担忧。
有一些状况下不去手动清除缓冲区而是忘记这件事多是一个更好的选择,由于读写可能不是必要的并且是相对花费大的。
Function: void **__fpurge** (FILE *stream)
Preliminary: | MT-Safe race:stream | AS-Unsafe corrupt | AC-Unsafe corrupt | See POSIX Safety Concepts.__fpurge
函数会把stream流的缓冲区清空,可是不会产生读写!声明在stdio_ext.h。
在打开一个流以后,你经过使用setvbuf
选择该流使用何种缓冲策略。
如下列出的函数和宏在头文件stdio.h中声明。
Function: int setvbuf (FILE *stream, char buf, int mode, size_t size)*
Preliminary: | MT-Safe | AS-Unsafe corrupt | AC-Unsafe lock corrupt | See POSIX Safety Concepts.这个函数是用来定义stream流该采用何种缓冲策略——能够是 _IOFBF
(满缓冲), _IOLBF
(行缓冲), or _IONBF
(无缓冲)。若是你输入的一个空指针做为buf参数,那么setvbuf
会自动使用malloc
申请一块内存,当你关闭流的时候,缓冲区会被清除释放掉。不然buf对应的内存块至少应该是size大小。你不该该释放掉buf对应的空间只要流尚未关闭。你应该确保buf对应的内存是静态存储的(例如使用malloc
)。使用一个自动存储期限的buf块不是一个好的选择——除非在退出当前块以前关掉了流。当buf对应的数组块是缓冲区的时候,stream流i/o函数会使用这个内存块做为一些内部用途——因此你不该该试着去直接访问这个数组的值当它被使用的时候。 setvbuf
成功时返回0,不然返回非零数当mode是不可取的或者要求不能被知足。
Macro: int **_IOFBF**
这个宏的值是一个整数常量表达式,能够被setvbuf
函数用来是缓冲区是满缓冲的。
Macro: int **_IOLBF**
这个宏的值是一个整数常量表达式,能够被setvbuf
函数用来是缓冲区是行缓冲的。
Macro: int **_IONBF**
这个宏的值是一个整数常量表达式,能够被setvbuf
函数用来是缓冲区是无缓冲的。
Macro: int BUFSIZ
这个宏的值是一个整数常量表达式,能够被setvbuf
函数用来表达size,这个值被保证最小是256。 BUFSIZ
是由操做系统选择的,以此来提升i/o的效率。因此使用 BUFSIZ
做为setvbuf
的大小值是一个很好的选择。事实上,你能够用过fstat
系统调用得到一个更好的值(在文件属性的 st_blksize
区域),参考 Attribute Meanings.有时候人们使用 BUFSIZ
做为申请内存空间的大小值(或者做为i/o操做的内存,例如fgets)——这没什么特别的理由,除了能提升一些i/o效率。
Function: void setbuf (FILE *stream, char buf)*
Preliminary: | MT-Safe | AS-Unsafe corrupt | AC-Unsafe lock corrupt | See POSIX Safety Concepts.If buf is a null pointer, the effect of this function is equivalent to calling setvbuf
with a mode argument of_IONBF
. Otherwise, it is equivalent to calling setvbuf
with buf, and a mode of _IOFBF
and a size argument of BUFSIZ
.The setbuf
function is provided for compatibility with old code; use setvbuf
in all new programs.若是buf是一个空指针,这个函数的效果等于setvbuf
使用_IONBF
.不然,等效于使用 setvbuf
和 _IOFBF
BUFSIZ
这两个参数。该函数是为了兼容一些老的代码,在新的程序中请使用setvbuf
.
Function: void setbuffer (FILE *stream, char buf, size_t size)*
Preliminary: | MT-Safe | AS-Unsafe corrupt | AC-Unsafe lock corrupt | See POSIX Safety Concepts.
省略...这个函数是为了兼容一些BSD的老旧代码。请使用setvbuf
.
Function: void setlinebuf (FILE *stream)
Preliminary: | MT-Safe | AS-Unsafe corrupt | AC-Unsafe lock corrupt | See POSIX Safety Concepts.
省略...这个函数是为了兼容一些BSD的老旧代码。请使用setvbuf
.
剩下一些不经常使用的函数就不翻译了。