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

news2024/11/18 22:47:13

文章目录

  • 如何理解缓冲区
    • 现象
    • 概念:文件缓冲区
    • 为什么要有缓冲区
    • 缓冲区在哪里
  • 自己封装一个简单的文件接口
    • 自主封装
      • 目标
    • 代码
    • 关于缓冲区
      • 强制刷新内核
  • 关于字符串格式化函数
    • 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));//这里不用加上\0
	
	fork();
	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.c
	gcc -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 0x4

typedef 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);
    else
        fd = 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);
    // 将用户缓冲区中的数据,通过系统调用接口,冲刷给OS
    write(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.指针置为NULL
    fp = 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.coloradmin.cn/o/1226176.html

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

相关文章

五、Linux目录结构

1.基本介绍 1.Linux的文件系统是采用级层式的树状目录结构&#xff0c;在此结构中的最上层是根目录"r/"&#xff0c;然后在此目录下再创建其他的目录。 2.深刻理解linux树状文件目录是非常重要的 3.记住一句经典的话&#xff1a;在Linux世界里&#xff0c;一切皆文件…

9、传统计算机视觉 —— 边缘检测

本节介绍一种利用传统计算机视觉方法来实现图片边缘检测的方法。 什么是边缘检测? 边缘检测是通过一些算法来识别图像中物体之间,或者物体与背景之间的边界,也就是边缘。 边缘通常是图像中灰度变化显著的地方,标志着不同区域的分界线。 在一张图像中,边缘可以是物体的…

机器学习---初识贝叶斯分类器

1. 引入问题 有两个可选的假设&#xff1a;病人有癌症、病人无癌症&#xff0c;可用数据来自化验结果&#xff1a;正和负- 有先验知识&#xff1a;在所有人口中&#xff0c;患病率是0.008&#xff0c;对确实有病的患者的化验准确率为98%&#xff0c;对确实无 病的患者的化验…

远程炼丹教程

【精选】深度学习远程炼丹&#xff1a;一文离线完成ubuntudockerpycharm环境配置_不能联网的电脑如何用docker配置深度学习环境_Yunlord的博客-CSDN博客文章浏览阅读2.6k次&#xff0c;点赞8次&#xff0c;收藏10次。本文详细讲解如何在离线服务器中安装dockerpycharm的远程深度…

Janus: 基于eBPF的5G实时AI控制器

O-RAN定义的RIC模型并不能很好支持对实时性有很高要求的用例&#xff0c;本文定义了一套基于eBPF的内联执行架构&#xff0c;从而可以将RIC的支持扩展到实时场景。原文: Taking 5G RAN Analytics and Control to a New Level[1] 摘要 Open RAN为5G无线接入网(RAN)引入了模块化和…

亚马逊Lightsail:云服务新篇章,轻松开启您的数字未来

文章目录 前言一、Lightsail是什么&#xff1f;Lightsail的优势使用场景 二、AWS lightsail创建VPS总结 前言 对于开发者而言&#xff0c;当你想构建系统架构时&#xff0c;你的面前就出现了两种选择&#xff0c;选择一是花时间去亲手挑选每个亚马逊云科技组件&#xff08;云服…

PS学习笔记——移动工具

文章目录 介绍文档内移动文档间移动 介绍 移动工具&#xff1a;用于移动图层中的对象&#xff0c;并且同一图层中的所有对象都将一起移动 选中移动工具后&#xff0c;选项栏中会出现“显示变换控件”&#xff0c;勾选后即可看见图层中的对象周围出现边框&#xff0c;可以进行缩…

【Go学习之 go mod】gomod小白入门,在github上发布自己的项目(项目初始化、项目发布、项目版本升级等)

参考 Go语言基础之包 | 李文周的博客Go mod的使用、发布、升级 | weiGo Module如何发布v2及以上版本1.2.7. go mod命令 — 新溪-gordon V1.7.9 文档golang go 包管理工具 go mod的详细介绍-腾讯云开发者社区-腾讯云Go Mod 常见错误的原因 | walker的博客 项目案例 oceanweav…

山西电力市场日前价格预测【2023-11-20】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2023-11-20&#xff09;山西电力市场全天平均日前电价为255.39元/MWh。其中&#xff0c;最高日前电价为436.50元/MWh&#xff0c;预计出现在18:00。最低日前电价为21.61元/MWh&#xff0c;预计出…

如何查看 class 文件的编译器版本

文章目录 原理分析解决方案其它解决方案javap 命令行工具 在平时的 Java 开发中&#xff0c;有时候我们需要知道某个 class 文件是由哪个版本的 Java 编译器编译生成的 原理分析 class 文件&#xff0c;即字节码文件&#xff0c;它有特定的二进制格式&#xff0c;这种格式是由…

『力扣刷题本』:环形链表(判断链表是否有环)

一、题目 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置&am…

接口调用微信公众号群发功能,绕过微信自身限制

微信群发功能要求要微信认证。微信认证要求要企业账号、而且需要认证费用。 本篇文章教大家非微信认证账号如何群发公众号信息 本篇文章基于python语言开发,其他的语言一样的方式,不需要拘泥于语言 注意事项: 要求有微信公众平台登陆状态,也就是Cookie数据, 如何通过Py…

统信UOS通过源码安装软件提示“configure: error: cannot run C compiled programs.”错误

1. 问题说明 使用源码的方式安装git软件&#xff0c;安装过程中出现两个错误。 编译错误“cannot run C compiled programs” XC:~/Downloads/git-2.42.1$ ./configure --prefix/home/software/git-2.42.1 configure: Setting lib to lib (the default) configure: Will try…

消息消费过程

前言 本文介绍下Kafka消费过程, 内容涉及消费与消费组, 主题与分区, 位移提交&#xff0c;分区再平衡和消费者拦截器等内容。 消费者与消费组 Kafka将消费者组织为消费组, 消息只会被投递给消费组中的1个消费者。因此, 从不同消费组中的消费者来看, Kafka是多播(Pub/Sub)模式…

腾讯云服务器公网带宽速度怎么样?上传下载实测!

腾讯云服务器公网带宽下载速度计算&#xff0c;1M公网带宽下载速度是128KB/秒&#xff0c;5M带宽下载速度是512KB/s&#xff0c;腾讯云10M带宽下载速度是1.25M/秒&#xff0c;腾讯云百科txybk.com来详细说下腾讯云服务器不同公网带宽实际下载速度以及对应的上传速度对照表&…

二十九、W5100S/W5500+RP2040树莓派Pico<Web socket Server>

文章目录 1 前言2 简介2 .1 什么是WebSocket协议&#xff1f;2.2 WebSocket协议工作原理2.3 WebSocket协议优点2.4 WebSocket应用场景 3 WIZnet以太网芯片4 WebSocket示例概述以及使用4.1 流程图4.2 准备工作核心4.3 连接方式4.4 主要代码概述4.5 结果演示 5 注意事项6 相关链接…

鸿蒙:Harmony开发基础知识详解

一.概述 工欲善其事&#xff0c;必先利其器。 上一篇博文实现了一个"Hello Harmony"的Demo&#xff0c;今天这篇博文就以Demo "Hello Harmony" 为例&#xff0c;以官网开发文档为依据&#xff0c;从鸿蒙开发主要的几个方面入手&#xff0c;详细了解一下鸿…

macOS 后台项目已添加 “Google Updater添加了可在后台运行的项目。你可以在“登陆项”设置中管理

文章目录 Intro解决查看三个文件夹分析 & 操作确认结果是否生效 Intro 我的macbook上经常弹出这样的通知狂&#xff1a; macOS 后台项目已添加 “Google Updater添加了可在后台运行的项目。你可以在“登陆项”设置中管理 不胜其扰&#xff0c;终于决定禁用它。以下为方法…

算法设计与分析【期中+期末复习知识点总结】(持续更新)

第1章&#xff1a;算法概述 算法&#xff1a;具有输入、输出、确定性、有限性。 程序&#xff08;算法数据结构程序&#xff09;&#xff1a;具有输入、输出、确定性&#xff08;注意&#xff1a;程序可以不满足有限性&#xff0c;如操作系统是在无限循环中执行的程序&#x…