printf函数打印(二)—— 缓冲区篇(文件读写再探究)
了解了printf打印时和缓冲区相关的部分内容
在上一个部分介绍了printf函数打印的完整过程
简单说就是 printf打印只知道要找 stdout,stdout包含的文件描述符 fd = 1
然后printf就去找 fd = 1对应的文件结构体,将数据写入到这个文件中
那么问题来了,在这个寻文件然后写文件的过程中,数据放在哪里??
===》答案是C缓冲区!
在用户层,每个文件有一个C缓冲区来存放数据(其实可以看作是一个数组);在内核层,也有对应的内核缓冲区来存放数据。每个文件的文件结构体中还有对应的属性来维护缓冲区
//在用户层,文件的表现形式是FILE结构体
struct FILE
{
int _fileno; //文件描述符
char* _IO_read_ptr; //维护缓冲区的相关内容
char* _IO_read_end;
char* _IO_read_base;
}
目录
1、原案例:将printf打印的内容输出到文件log.txt
一、数据缓存
1、数据缓存的框架
下面这个框架是计算机系统的局部
语言层 —— 我们平时书写代码用的 C/C++、java
OS —— 操作系统
2、刷新策略
我们要想在显示器上打印数据,那就必须要把C缓冲区中的数据刷新到内核缓冲区,然后再通过OS写入到硬件
刷新主要分下面三种:
(1) 不刷新(不缓冲)
(2) 行刷新(行缓冲): 遇到\n时,直接刷新到内核缓冲区
(3) 缓冲区满了,才刷新(全缓冲),比如向磁盘文件中写入
3、printf缓冲过程
一开始printf会将数据存入 I/O缓冲区,由于是行缓冲,行缓冲的特点是 遇到 \n 时会立马将C缓冲区的内容刷新到内核缓冲区
printf("hello, world\n");
二、阻止缓冲区刷新的相关案例
1、原案例:将printf打印的内容输出到文件log.txt
在上一部分介绍printf的打印过程时,分析过下面的代码
(1) 先关闭 fd = 1,也就是断开fd = 1 和stdout之间的联系
(2) 打开log.txt,根据文件描述符的分配原则,从低位的空位开始分配,所以log.txt的文件描述符fd=1
(3) printf 只知道找stdout ——》stdout包含的文件描述符fd = 1 ——》printf向fd = 1对应的文件写入内容 ——》没有打印到显示器,而是“打印”到log.txt文件
2、新案例:阻止printf输出内容到log.txt
上面是对前一部分内容的简单回顾,同时要和下面的内容进行比较
不知你是否发现,上面的代码有一行注释
一般来说,打开一个文件,写入或者读取结束后都要关闭这个文件
我们取消这个注释试试,然后看看测试结果
我们先清除log.txt原本的内容
根据测试结果发现log.txt中没有内容,本该写入 log.txt 的内容,现在却没有写入,仅因为加入了 一句
close(fd);
三、原因分析
一开始断开了fd=1和stdout文件之间的联系,然后打开了log.txt文件,现在fd = 1指向了log.txt文件
printf函数含 \n,所以hello,world会立刻从IO缓冲区刷新到内核缓冲区
但是现在运行了下面这句导致文件内核缓冲区和磁盘之间的联系断开了
close(fd);
原本进程退出以后,会进行Flush操作,相当于执行了fflush
但是现在断开了与硬件的联系,内核缓冲区无法输出,所以log.txt中什么都没有写入
四、解决方案
除了注释close(fd)这种方式,是否存在其他方式呢??
答案是 存在的!!
从图中我们会发现,所有的内容都被堵在了内核缓冲区中,无法输出到 log.txt
那么我们在close(fd)之前,把这些内容刷新到内核缓冲区,然后写到磁盘里就行了
fflush(stdout); //立即把IO缓冲区的内容立刻传给内核,让内核写回磁盘
这样的话,重新运行一下,我们就会发现,log.txt就会有printf要打印的内容了
五、文件读写再探究
之前有一篇是大致了解了文件的读写过程,现在了解了数据是先写到 用户层的IO缓冲区,然后再根据刷新策略刷新到文件内核缓冲区
现在可以再结合自己新学的内容再来了解一遍这个过程,现在我们要把文件缓冲区加进去
写文件并非是驱动函数 write_disk 一股脑全部写入磁盘,他会先把优先级较高的数据 放入文件内核缓冲区,然后我们再定期调用 write_disk函数将缓冲区的内容写入到磁盘中
假设现在系统调用函数write,带着一批数据"hello,world"进入了内核,然后这批数据会被放到文件内核缓冲区,定期调用 write_disk 将数据写入磁盘
红色线:目的是让OS循着这些线找到对应的内容
如写文件就需要知道写到哪个文件,数据暂存到哪
蓝色线:数据进入内核以后,是如何写入到磁盘的
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)