Linux系统为进程预定义了3个流:标准输入、标准输出、标准错误。进程启动时,会自动打开。
3个流分别对应文件描述符(int):STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO;
对应文件指针(FILE *):stdin、stdout、stderr;
标准I/O库为标准输入、标准输出流提供了缓存。标准错误默认没有缓冲。
提供缓冲的目的是尽可能减少read、write调用次数。
下图是一个调用fprintf与缓冲区关系的示例:
文件I/O:不带缓冲的I/O(unbuffered I/O)。不带缓冲是指函数实现时不带库缓冲区,从而每个读、写操作,都直接调用系统调用。
标准I/O:ANSI C建立的标准I/O模型,API包含在<stdio.h>中,不依赖内核,可移植性强。标准I/O库实现的缓存,统称简称库缓冲。
冲洗(flush)说明库缓冲的写操作。通常全缓冲写满以后,才会触发write系统调用,而冲洗操作会主动触发write,将所有用户控件输入write进内核高速缓存。对应系统调用fflush()。
对行缓冲有2个限制:
1)标准I/O库用来收集每行缓冲区长度固定,只要填满缓冲区,即使每写换行符,也进行I/O操作;
2)任何时候,只要通过标准I/O库从 一个不带缓冲的流,或者一个行缓冲的流得到数据,那么就会flush库的所有行缓冲输出流;
PS:标准错误流默认不带库缓冲。
ISO C要求下列缓冲特征:
很多系统默认实现:
setbuf
setbuf 使能、禁用长度为BUFSIZ的用户缓冲区buf。(BUFSIZ定义在<stdio.h>头文件中)。buf为NULL,代表关闭缓冲;buf指向一个长度为BUFSIZ的缓冲区,代表该流与全缓冲关联,如果该流与一个终端设备相关,那么有些系统可以将其设置为行缓冲。
setvbuf
setvbuf 精确说明所需要的缓存类型,用mode参数实现:
_IOFBF 全缓冲
_IOLBF 行缓冲
_IONBF 不带缓冲
setbuf与setvbuf关系
setbuf, setvbuf函数原型
#include <stdio.h> void setbuf(FILE *stream, char *buf); int setvbuf(FILE *stream, char *buf, int mode, size_t size);
fflush 函数可以强制冲洗一个流,使得库缓冲内容传送至内核(高速缓存)。
如果stream为NULL,将导致所有输出流被冲洗。
#include <stdio.h> int fflush(FILE *stream);