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

news2024/12/27 2:57:52

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

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

刷新缓冲逻辑图

在这里插入图片描述

自定义实现

mystdio.h
#pragma once 
#include <stdio.h>

#define NUM 1024
#define BUFF_NOME 0x1
#define BUFF_LINE 0x2
#define BUFF_ALL 0x4

typedef 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);
  //将用户缓冲区的数据,通过系统调用接口,冲刷给os
  write(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.coloradmin.cn/o/919420.html

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

相关文章

对《VB.NET通过VB6 ActiveX DLL调用PowerBasic及FreeBasic动态库》的改进

《VB.NET通过VB6 ActiveX DLL调用PowerBasic及FreeBasic动态库》使用的Activex DLL公共对象是需要先注册的。https://blog.csdn.net/weixin_45707491/article/details/132437502?spm1001.2014.3001.5501 Activex DLL事前注册&#xff0c;一次多用说起来也不是啥大问题&#x…

C语言小白急救 指针进阶讲解1

文章目录 指针一、 字符指针二、 指针数组三、数组指针1.数组的地址2.数组指针3.数组指针的应用 四、数组参数、指针参数1. 一维数组传参2.二维数组传参3.一级指针传参4.二级指针传参 五、函数指针1.函数的地址2.函数指针3.练习 指针 指针的概念&#xff1a; 1.指针就是个变量…

数据库(DQL,多表设计,事务,索引)

目录 查询数据库表中数据 where 条件列表 group by 分组查询 having 分组后条件列表 order by 排序字段列表 limit 分页参数 多表设计 一对多 多对多 一对一 多表查询 事物 索引 查询数据库表中数据 关键字&#xff1a;SELECT 中间有空格&#xff0c;加引…

H.265视频无插件流媒体播放器EasyPlayer.js播放webrtc断流重连的异常修复

H5无插件流媒体播放器EasyPlayer属于一款高效、精炼、稳定且免费的流媒体播放器&#xff0c;可支持多种流媒体协议播放&#xff0c;可支持H.264与H.265编码格式&#xff0c;性能稳定、播放流畅&#xff0c;能支持WebSocket-FLV、HTTP-FLV&#xff0c;HLS&#xff08;m3u8&#…

FxFactory 8 Pro Mac 苹果电脑版 fcpx/ae/motion视觉特效软件包

FxFactory pro for mac是应用在Mac上的fcpx/ae/pr视觉特效插件包&#xff0c;包含了成百上千的视觉效果&#xff0c;打包了很多插件&#xff0c;如调色插件&#xff0c;转场插件&#xff0c;视觉插件&#xff0c;特效插件&#xff0c;文字插件&#xff0c;音频插件&#xff0c;…

百望云华为云共建零售数字化新生态 聚焦数智新消费升级

零售业是一个充满活力和创新的行业&#xff0c;但也是当前面临很大新挑战和新机遇的行业。数智新消费时代&#xff0c;数字化转型已经成为零售企业必须面对的重要课题。 8 月 20 日-21日&#xff0c;以“云上创新 韧性增长”为主题的华为云数智新消费创新峰会2023在成都隆重召…

stm32之10.系统定时器

delay_s()延时秒 delay_ms()毫秒*1000 delay_us()微秒*1000000 微秒定时器代码 void delay_us(uint32_t n) { SysTick->CTRL 0; // Disable SysTick&#xff0c;关闭系统定时器 SysTick->LOAD SystemCoreClock/1000000*n-1; // 就是nus SysTick->LOAD Sys…

有趣的数学 数学建模入门二 一些理论基础

一、什么是数学建模? 现实世界中混乱的问题可以用数学来解决&#xff0c;从而产生一系列可能的解决方案来帮助指导决策。大多数人对数学建模的概念感到不舒服&#xff0c;因为它是如此开放。如此多的未知信息似乎令人望而却步。哪些因素最相关&#xff1f;但正是现实世界问题的…

C语言基础之——操作符(上)

本篇文章&#xff0c;我们将展开讲解C语言中的各种常用操作符&#xff0c;帮助大家更容易的解决一些运算类问题。 这里提醒一下小伙伴们&#xff0c;本章知识会大量涉及到二进制序列&#xff0c;不清楚二进制序列的小伙伴&#xff0c;可以去阅读我的另一篇文章《数据在内存中的…

Go【gin和gorm框架】实现紧急事件登记的接口

简单来说&#xff0c;就是接受前端微信小程序发来的数据保存到数据库&#xff0c;这是我写的第二个接口&#xff0c;相比前一个要稍微简单一些&#xff0c;而且因为前端页面也是我写的&#xff0c;参数类型自然是无缝对接_ 前端页面大概长这个样子 先用apifox模拟发送请求测试…

数据结构 day1

1>x.mind 2>间接定义结构体数组&#xff0c;进行4种方式的定义和初始化 3>定义结构体存储10辆车&#xff08;车的信息&#xff1a;品牌、单价、颜色&#xff09; 1.定义函数&#xff0c;实现循环输入 2.定义函数&#xff0c;实现排序 3.定义函数&#xff0c;计算红色车…

Windows10突然出现音频无法正常运行的解决方法

文章目录 前言 一 问题描述 二 解决方法 2.1 下载完成之后选择安装 2.2 选择其他位置来安装 2.3 静静等待安装完成 三 升级Windows显卡和声卡 总结 前言 本文主要介绍Windows里面的音频出现问题的解决方法 一 问题描述 Windows使用好好的&#xff0c;突然就出现声卡出…

安防监控视频平台EasyCVR视频汇聚平台和税务可视化综合管理应用方案

一、方案概述 为了确保税务执法的规范性和高效性&#xff0c;国家税务总局要求全面推行税务系统的行政执法公示制度、执法全过程记录制度和重大执法决定法制审核制度。为此&#xff0c;需要全面推行执法全过程记录制度&#xff0c;并推进信息化建设&#xff0c;实现执法全过程的…

Vue+Axios搭建二次元动态登录页面(mp4视频格式)

最近想做一个前端登录页面&#xff0c;背景好看的&#xff0c;格式中规中矩的&#xff0c;这么难&#xff1f;我自己创一个吧&#xff01; 效果图如下&#xff1a; 源码可以参考我的github&#xff0c;复制源码即可用&#xff1a;gym02/loginPage_Vue: 使用VueAxios搭建的动态…

微服务 Eureka

Eureka Eureka是Netflix开源的一个用于构建基于微服务架构的服务发现和注册中心技术。在微服务架构中&#xff0c;系统被拆分成多个小型、自治的服务&#xff0c;每个服务负责特定的业务功能。这些服务需要能够相互发现和通信&#xff0c;这就是Eureka所提供的功能。 Eureka主…

WSL2 window上高效运行Linux

1 WSL及优势 1.1 WSL简介 WSL&#xff08;Windows Subsystem for Linux&#xff09;是Windows操作系统中的一个功能&#xff0c;它允许用户在Windows环境下运行Linux应用程序。WSL提供了一个与Linux内核兼容的系统调用转发层&#xff0c;使得Linux二进制文件可以在Windows上直…

qt读取图像并且调整大小,避免撑爆qlable控件

qt读取图像并且调整大小&#xff0c;避免撑爆qlable控件 方式使用方式 方式 通过设置QLable的对齐方式来设置图片的对齐方式&#xff0c;自由的控制图片是显示在表格项的上下左右。 代码如下&#xff1a;QLabel *lable new QLabel(); //创建lable lable->setPixm…

stm32之16.外设定时器——TIM3

----------- 源码 void tim3_init(void) {NVIC_InitTypeDef NVIC_InitStructure;TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//使能TIM3的硬件时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//配置TIM3的定时时间TIM_TimeBaseStructure.TIM_Period 10000-1…

rabbitmq卸载重写安装3.8版本

卸载之前的版本的rabbitmq 卸载rabbitmq 卸载前先停止rabbitmq服务 /usr/lib/rabbitmq/bin/rabbitmqctl stop查看rabbitmq安装的相关列表 yum list | grep rabbitmq卸载rabbitmq相关内容 yum -y remove rabbitmq-server.noarch 卸载erlang 查看erlang安装的相关列表 …

详细介绍线程池的使用原理、参数介绍、优点、常见构造方法、使用案例、模拟实现

前言 创建和销毁一个线程时&#xff0c;这点损耗是微不足道的&#xff0c;但是当需要频繁的创建和销毁多个线程时&#xff0c;这个成本是不可忽视的&#xff0c;于是就有大佬创建了线程池&#xff0c;借助线程池来减少其中的成本。 目录 前言 一、线程池的使用原理 二、线程…