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、数据缓存的框架

2、刷新策略

3、printf缓冲过程

二、阻止缓冲区刷新的相关案例

 1、原案例:将printf打印的内容输出到文件log.txt

 2、新案例:阻止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缓冲区,然后再根据刷新策略刷新到文件内核缓冲区

OS管理文件的方式(文件读写的过程)_abs(ln(1+NaN))的博客-CSDN博客一个进程可以打开/创建多个文件,即 进程:打开的文件 = 1:n,一个进程是如何管理这些文件的?文件读写文件的完整过程是怎样的?https://blog.csdn.net/challenglistic/article/details/123940013

现在可以再结合自己新学的内容再来了解一遍这个过程,现在我们要把文件缓冲区加进去

写文件并非是驱动函数 write_disk 一股脑全部写入磁盘,他会先把优先级较高的数据 放入文件内核缓冲区,然后我们再定期调用 write_disk函数将缓冲区的内容写入到磁盘中

假设现在系统调用函数write,带着一批数据"hello,world"进入了内核,然后这批数据会被放到文件内核缓冲区,定期调用 write_disk 将数据写入磁盘

红色线:目的是让OS循着这些线找到对应的内容

              如写文件就需要知道写到哪个文件,数据暂存到哪

蓝色线:数据进入内核以后,是如何写入到磁盘的

  • 4
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值