当前位置: 首页 > news >正文

【LeetCode】模拟实现FILE以及认识缓冲区

模拟实现FILE以及认识缓冲区

      • 刷新缓冲逻辑图
      • 自定义实现
      • 如何强制刷新内核缓冲区
      • 例子

刷新缓冲逻辑图

在这里插入图片描述

自定义实现

mystdio.h
#pragma once 
#include <stdio.h>#define NUM 1024
#define BUFF_NOME 0x1
#define BUFF_LINE 0x2
#define BUFF_ALL 0x4typedef struct _MY_FILE
{int fd;//接受描述符的值int flags;//用来记录打开方式char outputbuffer[NUM];//缓冲区保存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);
int my_fflush(MY_FILE* fp);
mystdio.c
#include "mystdio.h"
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>MY_FILE* my_fopen(const char* path,const char* mode)
{//1.识别标志位,打开方式int flag = 0;if(strcmp(mode,"r") == 0) flag |= O_RDONLY;else if(strcmp(mode,"w") == 0) flag |= (O_CREAT | O_WRONLY | O_TRUNC);else if(strcmp(mode,"a") == 0) flag |= (O_CREAT | O_WRONLY | O_APPEND);else if(strcmp(mode,"r+") == 0) flag |= (O_WRONLY | O_RDONLY);else if(strcmp(mode,"w+") == 0) flag |= (O_CREAT | O_WRONLY | O_RDONLY | O_TRUNC);else if(strcmp(mode,"a+") == 0) flag |=(O_CREAT | O_WRONLY | O_RDONLY | O_APPEND);//2.尝试打开文件mode_t m = 0666;int fd = 0;if(flag | O_CREAT){fd = open(path,flag,m);}else {fd = open(path,flag);}if(fd < 0) return NULL;//3.给用户返回MY_FILE对象,需要先进行构建MY_FILE *mf = (MY_FILE*)malloc(sizeof(MY_FILE));if(mf == NULL){close(fd);return NULL;}//4.初始化MY_FILE对象mf->fd = fd;mf->flags = 0;mf->flags |= BUFF_LINE;memset(mf->outputbuffer,'\0',sizeof(mf->outputbuffer));mf->current = 0;//5.返回打开的文件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;
}//这里返回的是字节数,不是模拟实现的输入的、个数nmemb
size_t my_fwrite(const void* ptr,size_t size,size_t nmemb,MY_FILE* stream)
{//1、缓冲区如果已经满了,就直接写入if(stream->current == NUM)my_fflush(stream);//2.根据缓冲区剩余情况,进行数据拷贝即可size_t user_size = size * nmemb;size_t my_size = NUM - stream->current;size_t write = 0;if(my_size >= user_size) {memcpy(stream->outputbuffer + stream->current,ptr,user_size);//3.更新计数器字段stream->current += user_size;write = user_size;}else {//如果缓冲区内存不够存放的话,指挥存放它的最大值memcpy(stream->outputbuffer+stream->current,ptr,my_size);stream->current += my_size;write = 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);}}else {//TODO}return write;
}int my_fclose(MY_FILE* fp)
{assert(fp);//1.冲刷缓冲区if(fp->current > 0) my_fflush(fp);//2.关闭文件close(fp->fd);//3.释放堆空间free(fp);//4.指针置NULL --- 可以设置fp = NULL;return 0;
}
main.c
#include "mystdio.h"
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#define MYFILE "log.text"
int main()
{MY_FILE* fp = my_fopen(MYFILE,"w");if(fp == NULL) return 1;const char* str = "hello my my_fwrite";int cnt = 10;//操作文件while(cnt){char buffer[1024];snprintf(buffer,sizeof(buffer),"%s:%d\n",str,cnt--);size_t size = my_fwrite(buffer,strlen(buffer),1,fp);sleep(1);printf("当前成功写入:%lu个字节\n",size);}my_fclose(fp);return 0;
}

如何强制刷新内核缓冲区

根据文件描述符进行强制刷新

main.c
#include "mystdio.h"
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#define MYFILE "log.text"
int main()
{MY_FILE* fp = my_fopen(MYFILE,"w");if(fp == NULL) return 1;const char* str = "hello my my_fwrite";int cnt = 10;//操作文件while(cnt){char buffer[1024];snprintf(buffer,sizeof(buffer),"%s:%d\n",str,cnt--);if(cnt % 5 == 0){//当cnt是五的倍数的时候就会强制刷新一次my_fwrite(buffer,strlen(buffer),1,fp);}}my_fclose(fp);return 0;
}

在这里插入图片描述

例子

像我们进行scanf输入的时候,其实本身我们输入的是一串字符串,将这个字符串读入对应的缓冲区buff后,然后通过分解工作,进一步传入系统,系统,系统在通过一些指令输入输出想要的结果

http://www.lryc.cn/news/136960.html

相关文章:

  • 【Terraform学习】使用 Terraform 将 EC2 实例作为 Web 服务器启动(Terraform-AWS最佳实战学习)
  • WebGL 变量uniform、gl.getUniformLocation、gl.uniform4f及其同族函数相关
  • 【Visual Studio】生成.i文件
  • 本地生活服务平台加盟哪家公司好?
  • css-grid使用
  • springBoot提取一个List<?>中的某个字段集合
  • 【BUG】 ‘cv2.cv2‘ ‘wechat_qrcode_WeChatQRCode‘
  • 10 Mybatis
  • 【PHP】PHP的面向对象编程
  • Windows10突然出现音频无法正常运行的解决方法
  • Maven面试题大全及答案
  • 探究字符串匹配算法:暴力法与KMP算法的Java实现
  • 前端面试:【浏览器与渲染引擎】工作原理与渲染流程
  • PySide6学习笔记--gui小模版使用
  • 如何用Python实现冒泡排序
  • C++Qt堆叠窗体的使用案例
  • Linux之套接字UDP实现网络通信
  • Matlab绘制二值图像
  • Kali 网络参数的配置
  • 在 Redis 中处理键值 | Navicat
  • RedisTemplate和StringRedisTemplate的区别、对比
  • 使用ChatGPT进行创意写作的缺点
  • 七、任务优先级和Tick
  • Python——三目运算语句
  • C 实现Window/DOS 键盘监听事件
  • 在vue中使用 axios 访问 API
  • java八股文面试[java基础]——浅拷贝和深拷贝
  • 【DC-DC的原理图及Layout设计要点】
  • TCP可靠性机制
  • solidity0.8.0的应用案例13:数字签名及应用:NFT白名单