Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现

Linux文件系列: 深入理解缓冲区和C标准库的简易模拟实现

  • 一.缓冲区的概念和作用
  • 二.一个样例
  • 三.理解样例
    • 1.样例解释
    • 2.什么是刷新?
  • 四.简易模拟实现C标准库
    • 1.我们要实现的大致框架
    • 2.mylib.h的实现
      • 1.文件结构体的定义
      • 2.myfopen等等函数的声明
      • 3.完整mylib.h代码
    • 3.myfopen函数的实现
    • 4.myfwrite函数的实现
    • 5.myfflush函数的实现
    • 6.myfclose函数的实现
    • 7.演示
    • 8.完整代码
      • 1.mylib.h
      • 2.mylib.c
      • 3.main.c

一.缓冲区的概念和作用

在这里插入图片描述

二.一个样例

在这里插入图片描述
在这里插入图片描述

三.理解样例

1.样例解释

在这里插入图片描述
在这里插入图片描述

2.什么是刷新?

在这里插入图片描述

四.简易模拟实现C标准库

至此,我们理解了缓冲区的概念和作用,下面我们来简易模拟实现一下C标准库

1.我们要实现的大致框架

我们要实现的是:
在这里插入图片描述

2.mylib.h的实现

1.文件结构体的定义

1.首先要有一个文件结构体:

结构体当中
1.要封装文件描述符fd    设置成员变量fileno
2.用户级缓冲区buffer     大小宏定义为SIZE 4096
3.该文件所对应缓冲区的刷新策略 flag

刷新策略分别宏定义为

#define FLUSH_NONE 1        不刷新
#define FLUSH_LINE (1<<1)   行刷新
#define FLUSH_ALL (1<<2)    全刷新
4.缓冲区中有效数据的个数  end
#define SIZE 4096#define FLUSH_NONE 1
#define FLUSH_LINE (1<<1)
#define FLUSH_ALL (1<<2)typedef struct my_file
{int fileno;char buffer[SIZE];int end;//缓冲区中有效数据的个数(也就是最后一个有效数据的下一个位置)int flag;//缓冲区的刷新策略
}my_file;

2.myfopen等等函数的声明

在这里插入图片描述

1.myfopen:以mode的方式打开path这个文件

path:文件路径+文件名
mode:打开文件的方式
“r”:只读
“w”:覆盖写
“a”:追加写

2.myfwrite当中:把s字符串中前num个数据写入stream文件中

stream:要往哪个文件当中写入数据,stream是对应文件的结构体指针
s:有数据的字符串
num:要写入的数据个数

3.myfflush:刷新文件缓冲区
4.myfclose:关闭该文件

3.完整mylib.h代码

DFL_MODE : 打开文件的默认权限
在这里插入图片描述

3.myfopen函数的实现

在这里插入图片描述

my_file* myfopen(const char* path,const char* mode)
{int fd=0;int flag=0;if(strcmp(mode,"r")==0){flag |= O_RDONLY;}else if(strcmp(mode,"w")==0){flag |= (O_WRONLY | O_CREAT | O_TRUNC);}else if(strcmp(mode,"a")==0){flag |= (O_WRONLY | O_CREAT | O_APPEND);}if(flag & O_CREAT){fd=open(path,flag,DFL_MODE);}else{fd=open(path,flag);}//打开文件失败,设置errno错误码并返回NULLif(fd==-1){errno=2;return NULL;}//创建文件,设置fp的相应属性my_file* fp=(my_file*)malloc(sizeof(my_file));if(fp==NULL){errno=3;return NULL;}fp->fileno=fd;fp->flag=FLUSH_LINE;fp->end=0;return fp;
}

4.myfwrite函数的实现

在这里插入图片描述

//把s中的数据写入stream中
int myfwrite(const char* s,int num,my_file* stream)
{//保存旧的缓冲区的大小int pos=stream->end;//1.先写入用户级缓冲区memcpy(stream->buffer+pos,s,num);stream->end += num;//更新缓冲区大小//刷新策略:按行刷新if(stream->flag & FLUSH_LINE){//2.判断是否需要刷新缓冲区(判断是否有'\n')int flushit=0;while(pos < stream->end){if((stream->buffer[pos])=='\n'){flushit=1;break;}pos++;}if(flushit == 1){//3.刷新缓冲区:[0,pos]数据write(stream->fileno,stream->buffer,pos+1);//4.更新缓冲区 把[pos+1,count)的数据移动到[0,count-pos-2]当中//一共移动count-pos-1个数据//先求出要移动的最后一个数据的下标int count=stream->end;memmove(stream->buffer,stream->buffer+pos+1,count-pos-1);stream->buffer[count-pos-1]='\0';stream->end=count-pos-1;}}return num;
}

5.myfflush函数的实现

在这里插入图片描述

int myfflush(my_file* fp)
{if(fp->end > 0){write(fp->fileno,fp->buffer,fp->end);fp->end=0;}return 0;
}

6.myfclose函数的实现

在这里插入图片描述

int myfclose(my_file* fp)
{myfflush(fp);return close(fp->fileno);
}

7.演示

下面我们测试一下
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
跟我们所预想的一样

8.完整代码

1.mylib.h

#pragma once
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>#define SIZE 4096
#define DFL_MODE 0666#define FLUSH_NONE 1
#define FLUSH_LINE (1<<1)
#define FLUSH_ALL (1<<2)typedef struct my_file
{int fileno;char buffer[SIZE];int end;//缓冲区中有效数据的个数(也就是最后一个有效数据的下一个位置)int flag;//缓冲区的刷新策略
}my_file;my_file* myfopen(const char* path,const char* mode);int myfwrite(const char* s,int num,my_file* stream);int myfflush(my_file* fp);int myfclose(my_file* fp);

2.mylib.c

#include "mylib.h"my_file* myfopen(const char* path,const char* mode)
{int fd=0;int flag=0;if(strcmp(mode,"r")==0){flag |= O_RDONLY;}else if(strcmp(mode,"w")==0){flag |= (O_WRONLY | O_CREAT | O_TRUNC);}else if(strcmp(mode,"a")==0){flag |= (O_WRONLY | O_CREAT | O_APPEND);}if(flag & O_CREAT){fd=open(path,flag,DFL_MODE);}else{fd=open(path,flag);}//打开文件失败,设置errno错误码并返回NULLif(fd==-1){errno=2;return NULL;}//创建文件,设置fp的相应属性my_file* fp=(my_file*)malloc(sizeof(my_file));if(fp==NULL){errno=3;return NULL;}fp->fileno=fd;fp->flag=FLUSH_LINE;fp->end=0;return fp;
}//把s中的数据写入stream中
int myfwrite(const char* s,int num,my_file* stream)
{//保存旧的缓冲区的大小int pos=stream->end;//1.先写入用户级缓冲区memcpy(stream->buffer+pos,s,num);stream->end += num;//更新缓冲区大小//刷新策略:按行刷新if(stream->flag & FLUSH_LINE){//2.判断是否需要刷新缓冲区(判断是否有'\n')int flushit=0;while(pos < stream->end){if((stream->buffer[pos])=='\n'){flushit=1;break;}pos++;}if(flushit == 1){//3.刷新缓冲区:[0,pos]数据write(stream->fileno,stream->buffer,pos+1);//4.更新缓冲区 把[pos+1,count)的数据移动到[0,count-pos-2]当中//一共移动count-pos-1个数据//先求出要移动的最后一个数据的下标int count=stream->end;memmove(stream->buffer,stream->buffer+pos+1,count-pos-1);stream->buffer[count-pos-1]='\0';stream->end=count-pos-1;}}return num;
}int myfflush(my_file* fp)
{if(fp->end > 0){write(fp->fileno,fp->buffer,fp->end);fp->end=0;}return 0;
}int myfclose(my_file* fp)
{myfflush(fp);return close(fp->fileno);
}

3.main.c

#include "mylib.h"
int main()
{my_file* fp=myfopen("./log.txt","a");if(fp==NULL){perror("myfopen fail");return 1;}int cnt=10;const char* message="abc\ndef";while(cnt--){mywrite(message,strlen(message),fp);sleep(1);}myfclose(fp);return 0;
}

以上就是Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现的全部内容,希望能对大家有所帮助!

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

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

相关文章

xss——权限维持,钓鱼

后台植入cookie&#xff0c;表单劫持&#xff08;获得web权限才可以使用的&#xff09; 把后门植入后&#xff0c;当重新登录后台&#xff0c;就会触发这个代码&#xff0c;将数据发送给xss平台 第二种 我们可以通过这个找到&#xff0c;密码发送的地方&#xff0c;然后就可以…

Learn OpenGL 06 坐标系统

概述 局部坐标是对象相对于局部原点的坐标&#xff0c;也是物体起始的坐标。下一步是将局部坐标变换为世界空间坐标&#xff0c;世界空间坐标是处于一个更大的空间范围的。这些坐标相对于世界的全局原点&#xff0c;它们会和其它物体一起相对于世界的原点进行摆放。接下来我们…

康奈尔开源近10万份审稿意见,未来论文发表或将由AI定夺

大语言模型&#xff08;LLMs&#xff09;的进步为自动化论文评审开辟了新途径&#xff0c;这些模型在学术反馈领域展现出巨大潜力。自动化评审的核心优势在于其能够精准指出论文草稿的不足之处&#xff0c;助力作者优化研究。尽管已有丰富的同行评审数据&#xff0c;但现有自动…

map和set(二)——AVL树的简单实现

引入 二叉搜索树有其自身的缺陷&#xff0c;假如往树中 插入的元素有序或者接近有序&#xff0c;二叉搜索树就会退化成单支树&#xff0c;时间复杂度会退化成O(N)&#xff0c;因此 map、set等关联式容器的底层结构是对二叉树进行了平衡处理&#xff0c;即采用平衡树来实现。简…

2024年【G2电站锅炉司炉】考试题及G2电站锅炉司炉证考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年【G2电站锅炉司炉】考试题及G2电站锅炉司炉证考试&#xff0c;包含G2电站锅炉司炉考试题答案和解析及G2电站锅炉司炉证考试练习。安全生产模拟考试一点通结合国家G2电站锅炉司炉考试最新大纲及G2电站锅炉司炉考…

【海贼王的数据航海:利用数据结构成为数据海洋的霸主】探究二叉树的奥秘

目录 1 -> 树的概念及结构 1.1 -> 树的概念 1.2 -> 树的相关概念 1.3 -> 树的表示 1.4 -> 树在实际中的运用(表示文件系统的目录树结构) 2 -> 二叉树概念及结构 2.1 -> 二叉树的概念 2.2 -> 现实中的二叉树 2.3 -> 特殊的二叉树 2.4 ->…

储能系统--户用储能美洲市场(三)

2、美洲市场 2.1、美国户储发展驱动力 &#xff08;1&#xff09;电网老化带来配储需求&#xff0c;户用光储成家庭第二用电保障 美国大部分电网建于20世纪60和70年代&#xff0c;超70%以上的输电系统已经超过了25年&#xff0c;在高负荷运转或者外部环境承压时&#xff0c;…

波动数列 刷题笔记

思路分析 dp 找出状态转移方程 设d为a或者-b 代码 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N1010,MOD100000007; int get_mod(int a,int b){ return (a%bb)%b; …

每日五道java面试题之springMVC篇(二)

目录&#xff1a; 第一题. 请描述Spring MVC的工作流程&#xff1f;描述一下 DispatcherServlet 的工作流程&#xff1f;第二题. MVC是什么&#xff1f;MVC设计模式的好处有哪些?第三题. 注解原理是什么?第四题. Spring MVC常用的注解有哪些&#xff1f;第五题. SpingMvc中的…

vscode插件-TONGYILingma

通义灵码&#xff0c;是一款基于通义大模型的智能编码辅助工具&#xff0c;提供行级/函数级实时续写、自然语言生成代码、单元测试生成、代码注释生成、代码解释、研发智能问答、异常报错排查等能力&#xff0c;并针对阿里云 SDK/API 的使用场景调优&#xff0c;为开发者带来高…

04-ESP32S3-GPIO

ESP32S3-IDF GPIO GPIO简介 ESP32S3提供了多达45个物理GPIO管脚&#xff0c;这些管脚不仅可以作为通用的输入输出接口&#xff0c;还可以连接到内部外设信号。通过GPIO交换矩阵、IO MUX和RTC IO MUX&#xff0c;可以灵活地配置外设模块的输入信号来源于任何GPIO管脚&#xff0…

访问一次网站的全过程

目录 流程图&#xff1a; 一、应用层开始 1. 在浏览器输入https://www.baidu.com 2. DNS获取IP地址 3. 根据HTTP协议生成HTTP请求报文 应用层结束 二、传输层开始 4. TCP三次握手 传输层结束 三、网络层开始 5. IP寻址 6. ARP协议获取MAC地址 网络层结束 四、数据…