【Linux】C文件系统详解(三)——如何理解缓冲区以及自主封装一个文件接口

文章目录

  • 如何理解缓冲区
    • 现象
    • 概念:文件缓冲区
    • 为什么要有缓冲区
    • 缓冲区在哪里
  • 自己封装一个简单的文件接口
    • 自主封装
      • 目标
    • 代码
    • 关于缓冲区
      • 强制刷新内核
  • 关于字符串格式化函数
    • printf和scanf函数

如何理解缓冲区

以前写过一个进度条, 有一个输出缓冲区->这个缓冲区在哪里,为什么要存在
struct file [缓冲区]中的缓冲区与上面这个缓冲区有关系吗

1.先看现象->提出问题
2.提出文件缓冲区
3.解释问题

现象

int main()
{//C库fprintf(stdout,"hello fprintf\n");//系统调用const char* msg = "hello write\n";write(1,msg,strlen(msg));//这里不用加上\0fork();return 0
}

这样可以打印出来

hello fprintf
hello write

因为此时都是向显示器打印,是采用行缓冲,所以直接就刷新出来的(见下图中的解释)
但是如果我们重定向:./myfile > log.txt
结果不一样了:

hello write
hello fprintf
hello fprintf

但是如果不加fork();就不会产生这样的结果.
因为此时是普通文件,采用的刷新策略是全缓冲
所以真正的调用顺序应该是:在fork之前,write就直接打印进文件了,但是fwrite只是写在缓冲区中.在fork之后,fwrite的缓冲区中的文件变成了两份(写时拷贝),由此,会出现打印两次的现象.(下图中有解释)

概念:文件缓冲区

![[文件系统 2023-11-16 16.12.27.excalidraw|800]]

为什么要有缓冲区

可以节省调用者的时间:系统调用也是要花费大量时间的
进程可以继续做自己的事情,最后统一刷新

缓冲区在哪里

在你进行fopen打开文件的时候,会得到一个FILE结构体,缓冲区就在该结构体中
而调用write时,是系统调用,没有缓冲区,会直接刷新出来

自己封装一个简单的文件接口

自主封装

目标

用最简单的方式,呈现出对FILE的理解
特点:实现的是一个demo版本,重在呈现原理

代码

makefile

myfile:main.c myfile.cgcc -o $@ $^ 
.PHONY:clean
clean:rm -f myfile

myfile.h

#pragma once#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <malloc.h>
#include <unistd.h>
#include <assert.h>#define NUM 1024
#define BUFF_NONE 0x1
#define BUFF_LINE 0x2
#define BUFF_ALL 0x4typedef struct MY_FILE
{int fd;char outputbuffer[NUM];int flags; // 刷新方式int current;
} MY_FILE;MY_FILE *my_fopen(const char *path, const char *mode);
size_t my_fwrite(const void *ptr, size_t size, size_t nmemb, MY_FILE *stream);
int my_fclose(MY_FILE *fp);

myfile.c

#include "myfile.h"MY_FILE *my_fopen(const char *path, const char *mode)
{int flags = 0;if (strcmp(mode, "r") == 0)flags |= O_RDONLY;else if (strcmp(mode, "w") == 0)flags |= (O_WRONLY | O_CREAT | O_TRUNC);else if (strcmp(mode, "a") == 0)flags |= (O_WRONLY | O_CREAT | O_APPEND);mode_t m = 0666;int fd = 0;if (flags & O_CREAT)fd = open(path, flags, m);elsefd = open(path, flags);if (fd < 0){perror("open error");return NULL;}MY_FILE *mf = (MY_FILE *)malloc(sizeof(MY_FILE));if (mf == NULL){close(fd);return NULL;}mf->fd = fd;mf->flags = 0;mf->current = 0;mf->flags |= BUFF_LINE;// mf->outputbuffer[0] = 0;//初始化缓冲区memset(mf->outputbuffer, '\0', sizeof(mf->outputbuffer));return mf;
}int my_fflush(MY_FILE *fp)
{assert(fp);// 将用户缓冲区中的数据,通过系统调用接口,冲刷给OSwrite(fp->fd, fp->outputbuffer, fp->current);fp->current = 0;fsync(fp->fd);return 0;
}size_t my_fwrite(const void *ptr, size_t size, size_t nmemb, MY_FILE *stream)
{// 1. 缓冲区如果已经满了,就直接写入assert(stream);if (stream->current == NUM)my_fflush(stream);// 2. 根据缓冲区剩余情况,进行数据拷贝即可size_t user_size = size * nmemb;size_t my_size = NUM - stream->current;size_t writen = 0;if (my_size >= user_size){memcpy(stream->outputbuffer + stream->current, ptr, user_size);//3. 更新计数器字段stream->current += user_size;writen = user_size;}else{memcpy(stream->outputbuffer + stream->current, ptr, my_size);//3. 更新计数器字段stream->current += my_size;writen = my_size;}// 4. 开始计划刷新, 他们高效体现在哪里 -- TODO// 不发生刷新的本质,不进行写入,就是不进行IO,不进行调用系统调用,所以my_fwrite函数调用会非常快,数据会暂时保存在缓冲区中// 可以在缓冲区中积压多份数据,统一进行刷新写入,本质:就是一次IO可以IO更多的数据,提高IO效率if (stream->flags & BUFF_ALL){if (stream->current == NUM)my_fflush(stream);}else if (stream->flags & BUFF_LINE){if (stream->outputbuffer[stream->current - 1] == '\n')my_fflush(stream);}return writen;
}int my_fclose(MY_FILE *fp)
{assert(fp);// 1.关闭文件的时候,C要帮助我们进行冲刷缓冲区if (fp->current > 0){my_fflush(fp);}// 2.关闭文件close(fp->fd);// 3.释放堆空间free(fp);// 4.指针置为NULLfp = NULL;return 0;
}

关于缓冲区

1.历史上我们所谈的缓冲区指的是:用户级缓冲区,语言提供
2.用户层+内核->强制刷新内核

![[文件系统 2023-11-17 10.15.39.excalidraw|900]]

强制刷新内核

fsync(fp->fd);

关于字符串格式化函数

printf和scanf函数

int my_printf(const char* format,...)
{//1.先获取对应的变量a//2.定义缓冲区,对a转成字符串//2.1 fwrite(stdout,str);//3.将字串拷贝的stdout->buffer即可//4.结合刷新策略显示即可
}

![[Pasted image 20230325111337.png]]
![[Pasted image 20230325111513.png]]
完结.

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

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

相关文章

hyperledger fabric2.4测试网络添加组织数量

!!!修改内容比较繁琐,预期未来提供模板修改 修改初始配置文件,初始添加3个组织 organizations文件夹 /cryptogen文件夹下创建文件crypto-config-org3.yaml,内容如下: PeerOrgs:# ---------------------------------------------------------------------------# Org3# ----…

酷柚易汛ERP - 序列号盘点操作指南

1、应用场景 将系统中开启序列号的商品数量与与实际存放的数量进行对比。 2、主要操作 2.1 录入序列号 打开【盘点】-【序列号盘点】&#xff0c;新增序列号盘点单&#xff0c;点击【SN】按钮&#xff0c;在弹框中输入序列号。 支持扫描枪录入序列号支持复制粘贴序列号录入…

Java(二)(String的常见方法,ArrayList的常见方法)

String 创建string对象 package Helloworld;public class dome1 {public static void main(String[] args) {// 1.直接双引号得到字符串对象,封装字符串对象String name "lihao";System.out.println(name);// 2. new String 创建字符串对象,并调用构造器初始化字符…

力扣 字母异位词分组 哈表 集合

&#x1f468;‍&#x1f3eb; 力扣 字母异位词分组 ⭐ 思路 由于互为字母异位词的两个字符串包含的字母相同&#xff0c;因此对两个字符串分别进行排序之后得到的字符串一定是相同的&#xff0c;故可以将排序之后的字符串作为哈希表的键。 &#x1f351; AC code class Solut…

解析Spring Boot中的CommandLineRunner和ApplicationRunner:用法、区别和适用场景详解

在Spring Boot应用程序中&#xff0c;CommandLineRunner和ApplicationRunner是两个重要的接口&#xff0c;它们允许我们在应用程序启动后执行一些初始化任务。本文将介绍CommandLineRunner和ApplicationRunner的区别&#xff0c;并提供代码示例和使用场景&#xff0c;让我们更好…

公共字段自动填充-@TableField的fill实现(2)

TheadLocal 客户端发送的每次http请求&#xff0c;在服务端都会分配新的线程。因此登录检查过滤器、controller、元数据对象处理器属于一个线程。 TheadLocal是线程的局部变量&#xff1a; TheadLocal常用方法&#xff1a; 如何在元数据对象处理器中获取当前登录用户的id&…

Spring Boot 项目部署方案!打包 + Shell 脚本部署详解

文章目录 概要一 、profiles指定不同环境的配置二、maven-assembly-plugin打发布压缩包三、 分享shenniu_publish.sh程序启动工具四、linux上使用shenniu_publish.sh启动程序 概要 本篇和大家分享的是springboot打包并结合shell脚本命令部署&#xff0c;重点在分享一个shell程…

【MATLAB源码-第83期】基于matlab的MIMO中V-BALST结构ZF和MMSE检测算法性能误码率对比。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 在多输入多输出&#xff08;MIMO&#xff09;通信系统中&#xff0c;V-BLAST&#xff08;垂直波束形成层间空间时间编码技术&#xff09;是一种流行的技术&#xff0c;用于提高无线通信的数据传输速率和容量。它通过在不同的…

如何将 Docsify 项目部署到 CentOS 系统的 Nginx 中

文章目录 第一步&#xff1a;准备 CentOS 服务器第二步&#xff1a;安装 Node.js 和 Docsify第三步&#xff1a;初始化 Docsify 项目第四步&#xff1a;本地预览 Docsify 项目第五步&#xff1a;配置 Nginx 服务器第六步&#xff1a;重启 Nginx 服务器拓展&#xff1a;使用 HTT…

k8s-部署Redis-cluster(TLS)

helm pull bitnami/redis-cluster v8.3.8拉取源码生成证书 git clone https://github.com/redis/redis.git #文档 https://redis.io/docs/management/security/encryption/#getting-started生成你的TLS证书用官网的工具生成 1 Run ./utils/gen-test-certs.sh 生成根CA和服务…

Python 如何实现备忘录设计模式?什么是备忘录设计模式?Python 备忘录设计模式示例代码

什么是备忘录&#xff08;Memento&#xff09;设计模式&#xff1f; 备忘录&#xff08;Memento&#xff09;设计模式是一种行为型设计模式&#xff0c;用于捕获一个对象的内部状态&#xff0c;并在对象之外保存这个状态&#xff0c;以便在需要时恢复对象到先前的状态。这种模…

JAVA for 循环训练 Pattern

import java.util.Scanner;public class Pattern {public static void main(String[] args) {int[] arr {0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0};Scanner in new Scanner(System.in);System.out.print("请输入n:");int n in.nextInt();in.close();for …

【小沐学GIS】电子海图OpenCPN源代码编译和运行(VS2017 + Win10)

1、简介 免费的开源海图仪和船用GPS导航软件 https://opencpn.org/ 1.1 OpenCPN概述 OpenCPN是一款自由软件&#xff08;GPLv2&#xff09;&#xff0c;用于创建简洁的海图绘图仪和导航软件&#xff0c;可以在航行过程中使用或者作为计划工具。OpenCPN提供大量免费海图下载&a…

「项目阅读系列」go-gin-example star 6.5k!(1)

文章目录 准备工作适宜人群项目信息 项目结构代码阅读主要模块代码主函数模块router 路由模块auth 授权模块数据库 修改文章请求分析其他依赖 总结 准备工作 适宜人群 初学 go 语法&#xff0c;希望了解 go 项目的构建过程和方式。 项目信息 go-gin-example 项目是使用 gin…

037、目标检测-SSD实现

之——简单实现 目录 之——简单实现 杂谈 正文 1.类别预测层 2.边界框预测 3.多尺度输出联结做预测&#xff08;提高预测效率&#xff09; 4.多尺度实现 5.基本网络块 6.完整模型 杂谈 原理查看&#xff1a;037、目标检测-算法速览-CSDN博客 正文 1.类别预测层 类别…

Python学习(一)基础语法

文章目录 1. 入门1.1 解释器的作用1.2 下载1.3 基础语法输入输出语法与引号注释&#xff1a;变量&#xff1a; 数据类型与四则运算数据类型四则运算数据类型的查看type()数据类型的转换int()、int()、float() 流程控制格式化输出循环与遍历逻辑运算符list遍历字典dict遍历 跳出…

HarmonyOS开发Java与ArkTS如何抉择

在“鸿蒙系统实战短视频App 从0到1掌握HarmonyOS”视频课程中&#xff0c;很多学员来问我&#xff0c;在HarmonyOS开发过程中&#xff0c;面对Java与ArkTS&#xff0c;应该选哪样&#xff1f; 本文详细分析Java与ArkTS在HarmonyOS开发过程的区别&#xff0c;力求解答学员的一些…

Navicat 基于 GaussDB 主备版的快速入门

Navicat Premium&#xff08;16.2.8 Windows版或以上&#xff09; 已支持对GaussDB 主备版的管理和开发功能。它不仅具备轻松、便捷的可视化数据查看和编辑功能&#xff0c;还提供强大的高阶功能&#xff08;如模型、结构同步、协同合作、数据迁移等&#xff09;&#xff0c;这…

12-1- GAN -简单网络-线性网络

功能 随机噪声→生成器→MINIST图像。 训练方法 0 损失函数:gan的优化目标是一个对抗损失,是二分类问题,用BCELoss 1 判别器的训练,首先固定生成器参数不变,其次判别器应当将真实图像判别为1,生成图像判别为0 loss=loss(real_out, 1)+loss(fake_out, 0) 2 生成器的…

【Linux】-进程间通信-匿名管道通信(以及模拟一个进程池)

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树&#x1f388; &#x1f389;作者宣言&#xff1a;认真写好每一篇博客&#x1f4a4; &#x1f38a;作者gitee:gitee✨ &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 动态规划算法&#x1f384; 如 果 你 …