概述
内核空间与外围设备交换数据,用户空间与内核空间交换数据实际上是非常消耗时间的,应该尽量减少它们之间相互访问的次数,就应用了缓冲技术。其本质就是一次性读取大量数据(顺序读写)进缓冲,当需要数据的时候进入缓冲区读取数据,这样能够大大减少消耗的时候被消耗的时间,所以内核缓冲技术对于文件IO是非常重要的。
linux中的fopen函数是open函数的封装,fopen使用了FILE结构体保存缓冲数据,在进行read和write的时候减少了用户态和内核态的切换。open没有缓冲,每次读操作都直接从文件系统中获取数据,在进行read和write的时候每次都需要进行内核态和用户态的切换。当顺序访问文件,fopen系列的函数要比直接调用open系列快;如果随机访问文件open要比fopen快。
在上图中可以看到open每次打开文件都会产生一个结构体file来保存文件的读写信息,即使对于同时打开同一个文件,其结构体信息是不一样的。
标准IO缓冲区
1.不缓冲:一旦有数据,立即同步到外部设备。
2.全缓冲:(普通文件的默认类型);
a.一旦数据填满了缓冲区,立即同步到外部设备;
b.程序正常退出时,立即同步到外部设备;
c.遇到 fflush() 强制同步时,立即同步到外部设备;
d.关闭文件时,立即同步到外部设备;
e.读取文件时 , 立即同步到外部设备;
3.行缓冲:(最多只能缓冲一行)
a.一旦填满,立即同步到外部设备;
b.程序正常退出时,立即同步到外部设备;
c.遇到 fflush() 强制同步时,立即同步到外部设备;
d.关闭文件时,立即同步到外部设备;
e.读取文件时 , 立即同步到外部设备;
f.一旦遇到 '
' 时, 立即同步到外部设备;
相关API
setbuf ( 设置文件流的缓冲区 )
头文件:
#include <stdio.h>
定义函数:
void setbuf(FILE * stream, char * buf);
参数分析:
stream --> 为指定的文件流
buf --> 自定的缓冲区起始地址
无返回
setvbuf ( 设置文件流的缓冲区)
头文件:
#include <stdio.h>
定义函数:
int setvbuf(FILE * stream, char * buf, int mode, size_t size);
参数分析:
stream --> 指定的文件流
buf --> 指向自定的缓冲区起始地址
size --> 为缓冲区大小
mode --> 有下列几种
_IONBF 无缓冲 IO
_IOLBF 以换行为依据的无缓冲 IO
_IOFBF 完全无缓冲 IO. 如果参数 buf 为 NULL 指针, 则为无缓冲 IO.
返回值:
成功返回 0
失败返回 非零 , 错误号码会被设置
使用代码
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
char buff[1024];
memset( buff, ' ', sizeof( buff ));
fprintf(stdout, "启用全缓冲
");
setvbuf(stdout, buff, _IOFBF, 1024);
fprintf(stdout, "这里是 runoob.com
");
fprintf(stdout, "该输出将保存到 buff
");
fflush( stdout );
fprintf(stdout, "这将在程序退出时出现
");
fprintf(stdout, "最后休眠五秒钟
");
sleep(5);
return(0);
}
https://www.runoob.com/cprogramming/c-function-setvbuf.html
总结
1.通常磁盘上的文件是全缓冲区的;
2.标准输入和标准输入在指向终端设备时是行缓冲,而指向文件时,则是全缓冲的;
3.为了尽可能显示错误信息,标准错误是不带缓冲的。