【Linux操作系统】文件缓冲区

news2024/12/26 11:05:27

       🔥🔥 欢迎来到小林的博客!!
      🛰️博客主页:✈️林 子
      🛰️博客专栏:✈️ Linux
      🛰️社区 :✈️ 进步学堂
      🛰️欢迎关注:👍点赞🙌收藏✍️留言

目录

  • 用户级缓冲区
    • 缓冲区的验证
  • 缓冲区的继承

用户级缓冲区

实际上我们的C语言库函数,例如 printf,fprintf,puts 等。会把数据先写入C语言缓冲区,也就是用户级缓冲区。而不是直接写入系统内核缓冲区,如何验证呢? 我们先来看一份代码。

这份代码我们用的是C语言的fprintf 往 文件log.txt里写入hello。

#include<stdio.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/types.h>
#include<unistd.h>

int main()
{
  close(1);
  FILE* f = fopen("./log.txt","w");
  fprintf(f,"hello\n");
  fprintf(f,"hello\n");
  fprintf(f,"hello\n");
  fprintf(f,"hello\n");

  return 0;
}

我们可以发现,会把hello输入进文件log.txt中 。

在这里插入图片描述

那么我们在输入之后把 f的文件描述符关掉呢?

#include<stdio.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/types.h>
#include<unistd.h>

int main()
{
  close(1);
  FILE* f = fopen("./log.txt","w");
  fprintf(f,"hello\n");
  fprintf(f,"hello\n");
  fprintf(f,"hello\n");
  fprintf(f,"hello\n");
  close(f->_fileno);

  return 0;
}

我们就会惊奇的发现,log.txt 就不会被写入。

在这里插入图片描述

为什么会这样呢?主要是因为fprintf/printf/puts 等C语言库函数会先把内容放进C语言的缓冲区。或者说是用户层缓冲区,而用户级缓冲区的刷新策略是不一样的。

显示器刷新策略:行刷新,带/n 自动刷新

磁盘刷新策略: 缓冲区满了才刷新

而我们上面的代码是往磁盘文件写入,所以只有缓冲区满了,或者进程结束时自动刷新。而程序要在return之后在会结束,我们在return之前我们把该文件关闭了。那么最后刷新的时候进程就找不到对应的描述文件符。

当然,我们也可以在关闭之前手动fflush刷新一下。在关闭文件描述符之前刷新

#include<stdio.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/types.h>
#include<unistd.h>

int main()
{
  close(1);
  FILE* f = fopen("./log.txt","w");
  fprintf(f,"hello\n");
  fprintf(f,"hello\n");
  fprintf(f,"hello\n");
  fprintf(f,"hello\n");

  fflush(f);
  close(f->_fileno);

  return 0;
}

我们依然可以把内容写进文件。

在这里插入图片描述

缓冲区的验证

以上是我们的C语言缓冲区的验证,那么write/read等系统调用函数会经过C语言缓冲区吗?我们可以验证一下

#include<stdio.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/types.h>
#include<unistd.h>

int main()
{
  close(1);
  FILE* f = fopen("./log.txt","w");
  write(f->_fileno,"write\n",6); 
  fprintf(f,"hello\n");
  fprintf(f,"hello\n");
  fprintf(f,"hello\n");
  fprintf(f,"hello\n");

  close(f->_fileno);

  return 0;
}

然后我们会发现, write是可以正常写入,而fprintf的内容不能写入。

在这里插入图片描述

这说明了什么?这说明write不经过C语言缓冲区,而是直接写入系统内核缓冲区!因为write/read等函数是系统调用接口。 这也反向验证了 fprintf等一系列C语言库函数是先写入C语言缓冲区!然后根据刷新策略再刷新到系统缓冲区,再由系统缓冲区刷新到外设上。而C语言库函数的职能就是把字符串刷新到C语言缓冲区!!

在这里插入图片描述

缓冲区的继承

那么子进程会继承父进程的缓冲区吗? 我们先看看下面这段代码。

#include<stdio.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/types.h>
#include<unistd.h>

int main()
{
 //close(1);
  write(1,"write\n",6);
  fprintf(stdout,"hello\n");
  fprintf(stdout,"hello\n");
  fprintf(stdout,"hello\n");
  fprintf(stdout,"hello\n");

  fork();
  return 0;
}

然后我们运行发现每条语句都打印了一次

在这里插入图片描述

这没有问题,那么我们把它写入到文件呢?

#include<stdio.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/types.h>
#include<unistd.h>

int main()
{
  close(1);
  int fd = open("./log.txt",O_CREAT | O_WRONLY,0664);
  write(fd,"write\n",6);
  fprintf(stdout,"hello\n");
  fprintf(stdout,"hello\n");
  fprintf(stdout,"hello\n");
  fprintf(stdout,"hello\n");

  fork();
  return 0;
}

然后我们运行看看结果。

在这里插入图片描述

我们可以惊奇的发现,C语言库函数的内容被打印了2次! 而系统调用的内容只被打印了一次。

这说明了什么?这说明了子进程是可以继承父进程的缓冲区的。 为什么第一次打印到显示器每条语句只打印一次,而写进文件 C语言库函数写入却写入俩次? 这是因为显示器和磁盘刷新策略不同!!! 显示器是行刷新,而我们每个字符串后面加了个\n,所以刷新到C语言缓冲区后立马就被刷新到了系统缓冲区。但是磁盘的刷新策略是缓冲区满了才刷新,所以在创建子进程后。父进程的用户级缓冲区还没有被刷新,所以子进程就把这些内容继承下来了。而程序结束时会自动刷新缓冲区,所以父子进程的缓冲区都被刷新了,就出现了缓冲区内写入2次的结果。

这也更加验证了C库函数不是直接往系统缓冲区写入的,否则绝对不会出现写入俩次的情况!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/950018.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

设计模式--代理模式(Proxy Pattern)

一、什么是代理模式&#xff08;Proxy Pattern&#xff09; 代理模式&#xff08;Proxy Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许一个对象&#xff08;代理&#xff09;充当另一个对象&#xff08;真实对象&#xff09;的接口&#xff0c;以控制对该对象的…

DSP_TMS320F28377D_算法加速方法2_添加浮点运算快速补充库rts2800_fpu32_fast_supplement.lib

继上一篇博客DSP_TMS320F28377D_算法加速方法1_拷贝程序到RAM运行_江湖上都叫我秋博的博客-CSDN博客之后&#xff0c;本文讲第二种DSP算法加速的方法&#xff0c;该方法的加速效果很明显&#xff0c;但是加速范围仅限于32位浮点数下面这几种函数: 1 工程师的关注点 下面稍微解…

CentOS8安装mysql8.0.24

一、下载mysql安装包并解压 执行以下命令&#xff1a; # 创建mysql安装目录 mkdir /usr/local/mysql # 进入mysql安装目录 cd /usr/local/mysql/ # 下载mysql-8.0.24 wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.24-linux-glibc2.12-x86_64.tar.xz # 解压…

防静电出入门禁管理系统的功能和特点

防静电出入门禁管理系统是一种应用于电子设备生产、仓储物流等领域的门禁系统&#xff0c;旨在防止静电对于设备和产品的损害和干扰。该系统主要包括以下几个方面的功能和特点&#xff1a; 1. 门禁控制功能&#xff1a;通过在入口设置读卡器或生物识别设备&#xff08;如指纹、…

Java处理 CDT时区转换CST时区

例如&#xff1a;夏令营时间&#xff08;“Sat Aug 01 00:00:00 CDT 1987”&#xff09; //TODO CDT时区转换CST时区Date date new Date(value);TimeZone cdtTZ TimeZone.getTimeZone("America/Chicago");TimeZone cstTZ TimeZone.getTimeZone("America/Mexi…

SQL server数据库-定制查询-指定查询列/行、结果排序和Like模糊查询

本篇讲述进阶查询方法&#xff0c;如有语句不明确&#xff0c;可跳转本文专栏学习基础语法 1、指定列查询 特点 只会显示你输入的列的数据&#xff0c;会根据你输入的顺序进行显示&#xff0c;可以自定义查询显示时的列名 &#xff08;1&#xff09;只会显示你输入的列的数…

解析msvcp100.dll丢失的原因及修复方法,教你快速解决的方案

msvcp100.dll文件的丢失&#xff0c;其实也是属于dll丢失的其中一种&#xff0c;因为它是dll文件&#xff0c;大家记住&#xff0c;只要是后缀是dll的文件那么它就是dll文件&#xff0c;只要丢失了dll文件&#xff0c;那么其解决的方法都是大同小异的&#xff0c;唯一不同的是&…

分布式集群——jdk配置与zookeeper环境搭建

系列文章目录 分布式集群——jdk配置与zookeeper环境搭建 分布式集群——搭建Hadoop环境以及相关的Hadoop介绍 文章目录 系列文章目录 前言 一 zookeeper介绍与环境配置 1.1 zookeeper的学习 1.2 Zookeeper的主要功能 1.2.1 znode的节点类型 1.2.2 zookeeper的实现 …

【数据同步】如何快速同步第三方平台数据?

文章目录 前言1. 如何快速同步历史数据&#xff1f;2. 如何使用SFTP&#xff1f;2.1 账号权限控制2.2 统一数据格式2.3 使用job同步数据 3. 增量数据如何处理&#xff1f;4. 如何校验数据一致性&#xff1f; 前言 最近知识星球中有位小伙伴问了我一个问题&#xff1a;如何快速…

Navicat16连接Oracle报错:Oracle library is not loaded

1、有时候我们在用navicat的时候连接oracle的时候&#xff0c;它会提示我们Oracle library is not loaded&#xff0c;这时候我们要首先验证本机上是否已安装oracle的客户端&#xff0c;如果已安装客户段&#xff0c;navicat中的oci.dll选择我们安装的客户段的oci.dll文件 2、…

【C进阶】深度剖析数据在内存中的存储

目录 一、数据类型的介绍 1.类型的意义&#xff1a; 2.类型的基本分类 二、整形在内存中的存储 1.原码 反码 补码 2.大小端介绍 3.练习 三、浮点型在内存中的存储 1.一个例子 2.浮点数存储规则 一、数据类型的介绍 前面我们已经学习了基本的内置类型以及他们所占存储…

PyTorch 深度学习实践 第10讲刘二大人

总结&#xff1a; 1.输入通道个数 等于 卷积核通道个数 2.卷积核个数 等于 输出通道个数 1.单通道卷积 以单通道卷积为例&#xff0c;输入为&#xff08;1,5,5&#xff09;&#xff0c;分别表示1个通道&#xff0c;宽为5&#xff0c;高为5。假设卷积核大小为3x3&#xff0c…

直线模组选型的参考要素有哪些?

直线模组在自动化行业领域使用广泛&#xff0c;在不同设备运用直线模组&#xff0c;相对来说区别还是比较大的&#xff0c;而选择直线模组也是有很多要素决定的&#xff0c;因此懂得直线模组的选型也是至关重要的。 很多人都觉得选型是比较困难的&#xff0c;尤其是对于公司采购…

Ansible学习笔记10

1、在group1的被管理机里的mariadb里创建一个abc库&#xff1b; 1&#xff09; 然后我们到agent主机上进行检查&#xff1a; 可以看到数据库已经创建成功。 再看几个其他命令&#xff1a; #a组主机重启mysql&#xff0c;并设置开机自启 ansible a -m service -a "namemy…

Java中异或操作和OTP算法

最近在研究加密算法&#xff0c;发现异或操作在加密算法中用途特别广&#xff0c;也特别好用。下面以Java语言为例&#xff0c;简单记录一下异或操作&#xff0c;以及在算法中的使用&#xff0c;包括常用的OTP算法。 一&#xff0c;异或操作特征 1&#xff0c; 相同出0&#…

二分类问题使用rmse训练会是什么结果

通常情况下&#xff0c;使用均方根误差&#xff08;RMSE&#xff0c;Root Mean Square Error&#xff09;来训练二分类问题可能并不是最优选择&#xff0c;因为RMSE通常用于衡量连续值的预测误差&#xff0c;而不是分类问题。二分类问题更常用的衡量标准是交叉熵损失&#xff0…

行业追踪,2023-08-30

自动复盘 2023-08-30 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…

java八股文面试[数据库]——MySql聚簇索引和非聚簇索引索引区别

聚集索引和非聚集索引 聚集索引和非聚集索引的根本区别是表记录的排列顺序和与索引的排列顺序是否一致。 1、聚集索引 聚集索引表记录的排列顺序和索引的排列顺序一致&#xff08;以InnoDB聚集索引的主键索引来说&#xff0c;叶子节点中存储的就是行数据&#xff0c;行数据在…

使用errors.Wrapf()代替log.Error()

介绍不同语言的错误处理机制: Error handling patterns[1] Musings about error handling mechanisms in programming languages[2] 项目中 main调func1&#xff0c;func1调取func2... 这样就会出现很多的 if err ! nil { log.Printf()} , 在Kibana上查看时会搜到多条日志, 需要…