带你彻底搞懂缓冲区

目录

一.缓冲区概念介绍

(一).基本概念

(二).为什么需要缓冲区?

二.剖析缓冲区本质

(一). 缓冲区刷新规则

(二).不同属性文件的默认刷新规则

(三).谁在制造缓冲区?

(四).缓冲区的位置

(五).总结


一.缓冲区概念介绍

(一).基本概念

所谓缓冲区,就是当我们在编程向文件中输入数据时,数据不会直接写入文件,而是先写入一个名为缓冲区的区域,经过对缓冲区的刷新后才能写入文件中

可以通过此例作以证明:

下例中,我们打开一个文件,使用fwrite向其中输入数据,第一次采用直接使用close关闭文件,第二次采用刷新缓冲区fflush后close关闭文件。看看有什么不同:

//代码一
int main()
{
    FILE* fp = fopen("log.txt", "w");
    const char* str = "hello world\n";
    fwrite(str, strlen(str), 1, fp);
    close(fp->_fileno);//系统调用接口,fileno:即文件描述符fd
    return 0;
}
//代码二
int main()
{
    FILE* fp = fopen("log.txt", "w");
    const char* str = "hello world\n";
    fwrite(str, strlen(str), 1, fp);
    fflush(fp);//刷新缓冲区
    close(fp->_fileno);
    return 0;
}

 我们发现,如果没有刷新缓冲区那么数据将无法写入数据,这说明fwrite确实是先将数据写入缓冲区再写入文件。

(二).为什么需要缓冲区?

因为当我们向文件中写入数据时,这是一个IO的过程。IO的次数越多,那么时间浪费越多,效率越低。如果使用一个东西预先存储这些数据,当到达一定规模时统一写入文件,那么IO的次数就会减少,进而效率提升。

因此,缓冲区存在的意义就是通过减少IO次数达到效率上的提升

二.剖析缓冲区本质

在上述文件中,我们可能会好奇,为什么写入操作使用c语言接口fwrite,而关闭操作使用系统调用接口close?

回答这个问题,需要我们一点点搞清楚缓冲区的本质:

(一). 缓冲区刷新规则

严格来讲,缓冲区共有四种刷新规则:立即刷新、行刷新、满刷新、强制刷新

①立即刷新

所谓立即刷新就是字面意义,每当向缓冲区中写入数据就刷新一次。

②行刷新

当在数据中检测到换行符'\n'时刷新,这叫行刷新。

比如向显示器printf("hello world\n");时会执行行刷新。

③满刷新

当缓冲区中数据已满时刷新,这叫满刷新。

④强制刷新

即由人强制缓冲区执行刷新操作,例如fflush就是一种强制刷新。

(二).不同属性文件的默认刷新规则

不同文件对应刷新规则不同,这是主要是由文件使用性质决定的。

对于标准输入输出流(显示器、键盘)来说,其采用行刷新策略。

这是因为它们在使用时,需要考虑使用者的感受。试想一下,如果你写了超大一片文章,显示器一口气显示出来便于阅读还是一行行显示便于阅读?

对于磁盘文件来说,其采用满刷新策略。

这是因为磁盘文件数据并不是及时阅读的,刷新的次数越少效率越高。

因此,即便我们写入的文字中有换行符,缓冲区也不会立即刷新。

(三).谁在制造缓冲区?

本小节将回答大标题二开头的那个问题。

在回答这个问题前,请大家跟我一起看一段代码:

这两段代码唯一的区别就是一个使用close关闭文件,一个使用fclose关闭文件:

//代码一
int main()
{
    FILE* fp = fopen("log.txt", "w");
    const char* str = "hello world\n";
    fwrite(str, strlen(str), 1, fp);
    close(fp->_fileno);//系统调用接口
    return 0;
}
//代码二
int main()
{
    FILE* fp = fopen("log.txt", "w");
    const char* str = "hello world\n";
    fwrite(str, strlen(str), 1, fp);
    fclose(fp);//c接口
    return 0;
}

看看结果有什么不同:

通过结果我们发现,当使用系统接口时,缓冲区并没有被刷新;而使用c语言接口,缓冲区被刷新。根据我们已知的认识,fclose内部封装了close。那么就是说缓冲区是在fclose内部被刷新后,再调用的close系统接口

因此,所谓缓冲区,其实是c语言提供的

这样之前的问题也就有了答案:我们之所以没有使用c语言接口而是使用系统的close,是因为fclose内部会刷新缓冲区,根本无法观察到差异。而close作为系统调用接口,其并没有缓冲区,会直接关闭文件,进而缓冲区内的数据也就无法写入了

那么问题又来了,缓冲区在哪里呢?

(四).缓冲区的位置

开门见山直接回答:在FILE结构体中

每当我们打开一个文件时,c语言都会为其创建一个FILE类型的结构体,用以记录该文件的相关信息,比如文件大小,文件描述符之类的。当然,其内部也会有一个字符型指针指向一片动态开辟的空间,而这个空间就是缓冲区!

一切请以实物为准,我们直接看FILE结构体源代码

 

(五).总结

缓冲区是由语言层面提供,在c语言中在FILE结构体内部本质上是在堆上开辟的一段空间,通过字符型指针对其操作。每当打开一个文件时,都会创建一个FILE结构体,因此每一个文件都有与之对应的缓冲区

最初的90%的代码用去了最初90%的开发时间,余下的10%的代码用掉另外90%的开发时间

——Tom Cargill


如有错误,敬请斧正

  • 12
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

就要 宅在家

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值