【Linux】第二十四站:模拟实现C语言文件标准库

文章目录

  • 一、实现细节
    • 1.需要实现的函数
    • 2.fopen的实现
    • 3.fclose
    • 4.fwrite
    • 5.测试
    • 6.缓冲区的实现
    • 7.FILE中缓冲区的意义
  • 二、完整代码

一、实现细节

1.需要实现的函数

#include "mystdio.h"int main()
{_FILE* fp = _fopen("test.txt","w");if(fp == NULL) return 1;const char* msg = "hell world";_fwrite(fp,msg,strlen(msg));_fclose(fp);return 0;
}

如上代码所示,就是我们需要实现的功能

也就是说,我们在头文件中需要写出以下的代码

#ifndef __MYSTDIO_H__
#define __MYSTDIO_H__#include <string.h>
typedef struct IO_FILE
{int fileno; 
}_FILE;
_FILE* _fopen(const char* filename, const char* flag);
int _fwrite(_FILE* fp, const char* s, int len);
void _fclose(_FILE* fp);#endif

2.fopen的实现

它的实现逻辑是这样的,首先我们要根据对应的flag去选择以什么样的方式去打开某个文件。

当文件成功打开以后,我们需要创建这个文件的结构体对象,然后将文件描述符写入到文件结构体中。最后返回这个文件的结构体

_FILE* _fopen(const char* filename, const char* flag)
{assert(filename);assert(flag);int f = 0;int fd = -1;if(strcmp(flag, "w") == 0){f = (O_WRONLY|O_CREAT|O_TRUNC);fd = open(filename, f, FILE_MODE);}else if(strcmp(flag, "a") == 0) {f = (O_WRONLY|O_CREAT|O_APPEND);fd = open(filename, f, FILE_MODE);}else if(strcmp(flag, "r") == 0) {f = O_RDONLY;fd = open(filename, f);}else{return NULL;}if(fd == -1){return NULL;}_FILE* fp = (_FILE*)malloc(sizeof(_FILE));if(fp == NULL){return NULL;}fp->fileno = fd;return fp;
}

3.fclose

对于文件的关闭,我们只需要利用close这个系统调用接口,关闭对应的文件描述符即可,然后释放掉这个文件结构体

void _fclose(_FILE* fp)
{if(fp == NULL){return;}close(fp->fileno);free(fp);
}

4.fwrite

int _fwrite(_FILE* fp, const char* s, int len)
{return write(fp->fileno,s,len);    
}

对于这个fwrite而言,它只需要利用write这个接口直接去调用这个写入的接口即可

5.测试

我们现在可以简单的去跑一下代码

image-20231130163432240

image-20231130163342862

如果我们将代码改为追加模式

image-20231130163456193

那么运行结果为

image-20231130163550599

所以这样我们就不用再去使用系统调用了,而是直接使用库函数即可。

这就是一层封装,在windows等其他操作系统也是一样,我们只需要根据其对应的系统调用写上对应的代码即可。这样就可以实现跨平台性了

像java中的jvm也是一样的,它本身就是用C/C++写的,然后java的代码就是跑在它的上面的

6.缓冲区的实现

在这里我们不去考虑一些异常处理,也不考虑一些局部的问题

image-20231130165707739

在C语言中,即存在输入缓冲区,也有输出缓冲区。

对于输入缓冲区,就是我们在输入的时候,我们的设备只认识字符,即便是123也会将其认为字符1字符2字符3。

image-20231130165832594

image-20231130165853368

即对于上面的这些接口,我们也可以看到,这些都是void类型,也就是说并不关心具体是什么类型。

具体这些数据是什么类型全部交由上层来解释。所以我们的键盘显示器都叫做字符输入输出设备。所以才可以格式化输入输出

总之全部当作字符来出来

我们现在只实现一个输出缓冲区

image-20231130175546868

flag代表着的是刷新的模式,有无刷新,行刷新,全刷新三种策略。我们分别用宏来表示

最终我们的代码改为如下

#include "mystdio.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>#define FILE_MODE 0666//"w","a",r
_FILE* _fopen(const char* filename, const char* flag)
{assert(filename);assert(flag);int f = 0;int fd = -1;if(strcmp(flag, "w") == 0){f = (O_WRONLY|O_CREAT|O_TRUNC);fd = open(filename, f, FILE_MODE);}else if(strcmp(flag, "a") == 0) {f = (O_WRONLY|O_CREAT|O_APPEND);fd = open(filename, f, FILE_MODE);}else if(strcmp(flag, "r") == 0) {f = O_RDONLY;fd = open(filename, f);}else{return NULL;}if(fd == -1){return NULL;}_FILE* fp = (_FILE*)malloc(sizeof(_FILE));if(fp == NULL){return NULL;}fp->fileno = fd;fp->flag = FLUSH_LINE;fp->out_pos = 0;return fp;
}
int _fwrite(_FILE* fp, const char* s, int len)
{memcpy(&(fp->outbuffer[fp->out_pos]), s, len);fp->out_pos += len;if(fp->flag&FLUSH_NOW){write(fp->fileno, fp->outbuffer, fp->out_pos);fp->out_pos = 0;}else if(fp->flag&FLUSH_LINE){if(fp->outbuffer[fp->out_pos-1]=='\n'){write(fp->fileno, fp->outbuffer, fp->out_pos);fp->out_pos = 0;}}else if(fp->flag&FLUSH_ALL){if(fp->out_pos == SIZE){write(fp->fileno, fp->outbuffer, fp->out_pos);fp->out_pos = 0;}}return len;
}
void _fclose(_FILE* fp)
{if(fp == NULL){return;}close(fp->fileno);free(fp);
}

对于main.c中,代码改为如下

#include "mystdio.h"
#include <unistd.h>
#define Filename "test.txt"int main()
{_FILE* fp = _fopen(Filename,"w");if(fp == NULL) return 1;const char* msg = "hell world\n";int cnt = 10;while(cnt){_fwrite(fp,msg,strlen(msg));sleep(1);cnt--;}_fclose(fp);return 0;
}

运行结果为

image-20231130175724942

以上是行刷新的策略

我们可以试一下全刷新

image-20231130175852601

其实我们发现结果不对,因为即便进程退出了也没有刷新出来

image-20231130180102790

这是因为我们缺少了在进程退出时强制刷新的部分,如下所示

image-20231130180752407

image-20231130180738897

7.FILE中缓冲区的意义

因为,如果我们写一次就往操作系统写一次,这样效率太低,不如暂一大批,然后再跟操作系统去交互。

即让C语言的接口调用起来变得更快。

二、完整代码

mystdio.h

#ifndef __MYSTDIO_H__
#define __MYSTDIO_H__#include <string.h>
#define SIZE 1024#define FLUSH_NOW 1
#define FLUSH_LINE 2
#define FLUSH_ALL 4typedef struct IO_FILE
{int fileno; //char inbuffer[SIZE];//int in_pos;char outbuffer[SIZE];int out_pos;int flag;
}_FILE;
_FILE* _fopen(const char* filename, const char* flag);
int _fwrite(_FILE* fp, const char* s, int len);
void _fclose(_FILE* fp);#endif

mystdio.c

#include "mystdio.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>#define FILE_MODE 0666//"w","a",r
_FILE* _fopen(const char* filename, const char* flag)
{assert(filename);assert(flag);int f = 0;int fd = -1;if(strcmp(flag, "w") == 0){f = (O_WRONLY|O_CREAT|O_TRUNC);fd = open(filename, f, FILE_MODE);}else if(strcmp(flag, "a") == 0) {f = (O_WRONLY|O_CREAT|O_APPEND);fd = open(filename, f, FILE_MODE);}else if(strcmp(flag, "r") == 0) {f = O_RDONLY;fd = open(filename, f);}else{return NULL;}if(fd == -1){return NULL;}_FILE* fp = (_FILE*)malloc(sizeof(_FILE));if(fp == NULL){return NULL;}fp->fileno = fd;//fp->flag = FLUSH_LINE;fp->flag = FLUSH_ALL;fp->out_pos = 0;return fp;
}
int _fwrite(_FILE* fp, const char* s, int len)
{memcpy(&(fp->outbuffer[fp->out_pos]), s, len);fp->out_pos += len;if(fp->flag&FLUSH_NOW){write(fp->fileno, fp->outbuffer, fp->out_pos);fp->out_pos = 0;}else if(fp->flag&FLUSH_LINE){if(fp->outbuffer[fp->out_pos-1]=='\n'){write(fp->fileno, fp->outbuffer, fp->out_pos);fp->out_pos = 0;}}else if(fp->flag&FLUSH_ALL){if(fp->out_pos == SIZE){write(fp->fileno, fp->outbuffer, fp->out_pos);fp->out_pos = 0;}}return len;
}
void _fflush(_FILE* fp)
{if(fp->out_pos > 0){write(fp->fileno, fp->outbuffer, fp->out_pos);fp->out_pos = 0;}
} 
void _fclose(_FILE* fp)
{if(fp == NULL){return;}_fflush(fp);close(fp->fileno);free(fp);
}

main.c

#include "mystdio.h"
#include <unistd.h>
#define Filename "test.txt"int main()
{_FILE* fp = _fopen(Filename,"w");if(fp == NULL) return 1;const char* msg = "hell world\n";int cnt = 10;while(cnt){_fwrite(fp,msg,strlen(msg));sleep(1);cnt--;}_fclose(fp);return 0;
}

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

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

相关文章

超大规模集成电路设计----基本概念(二)

本文仅供学习&#xff0c;不作任何商业用途&#xff0c;严禁转载。绝大部分资料来自----数字集成电路——电路、系统与设计(第二版)及中国科学院段成华教授PPT 超大规模集成电路设计----基本概念&#xff08;二&#xff09; 简短的历史回顾(A Brief Historical Perspective)第…

观察者设计模式

package com.jmj.pattern.observer;/*抽象观察者类*/ public interface Observer {void update(String message);}package com.jmj.pattern.observer;/*** 抽象主题角色*/ public interface Subject {//添加观察者对象void attach(Observer observer);//删除订阅者void detach(…

LeetCode(51)简化路径【栈】【中等】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 简化路径 1.题目 给你一个字符串 path &#xff0c;表示指向某一文件或目录的 Unix 风格 绝对路径 &#xff08;以 / 开头&#xff09;&#xff0c;请你将其转化为更加简洁的规范路径。 在 Unix 风格的文件系统中&#xff…

SmartSoftHelp8,FrameCode极速二次开发框架源码

1.winform outlook style UI C/S 极速开发框架 netframework 2.0 2.winform toolbar style UI C/S 极速开发框架 netframework 2.0 3.WPF toolbar style UI C/S 极速开发框架 netframework 4.0 4.Xadmin-UI jquery B/S 极速开发框架 5.Vue element UI B/S…

Presto基础学习--学习笔记

1&#xff0c;Presto背景 2011年&#xff0c;FaceBook的数据仓库存储在少量大型hadoop/hdfs集群&#xff0c;在这之前&#xff0c;FaceBook的科学家和分析师一直靠hive进行数据分析&#xff0c;但hive使用MR作为底层计算框架&#xff0c;是专为批处理设计的&#xff0c;但是随…

在vue3项目嵌套 导入老项目 jQuery项目,减少重复开发

背景&#xff1a; 公司管理平台项目一直是前辈用jQuery做的&#xff0c;为扩展根据自身的技术栈&#xff0c;将jQuery的老项目嵌套入vue3的框架&#xff0c;新功能用vue开发&#xff0c;旧的功能不动直接在vue3用iframe容器来展示 嵌套步骤 2种方式嵌套&#xff0c;一个是已…

微机原理——并行接口8255学习1

目录 并行接口特点 可编程并行接口芯片8255 8255端口地址 8255的三种工作方式 8255的两种命令&#xff08;方式命令和C端口命令&#xff09; 由用户扩展的并行接口8255的应用 声光报警器接口设计 步进电机控制接口设计 PA端口实现跑马灯 PB端口实现按键输入 并行接口特…

同旺科技 USB TO SPI / I2C --- 调试W5500_Ping测试

所需设备&#xff1a; 内附链接 1、USB转SPI_I2C适配器(专业版); 首先&#xff0c;连接W5500模块与同旺科技USB TO SPI / I2C适配器&#xff0c;如下图&#xff1a; 设置寄存器&#xff1a; SHAR&#xff08;源MAC地址寄存器&#xff09;&#xff0c;该寄存器用来设置源MAC…

【预计IEEE出版|EI征稿通知】第六届下一代数据驱动网络国际学术会议 (NGDN 2024)

第六届下一代数据驱动网络国际学术会议 (NGDN 2024) The Sixth International Conference on Next Generation Data-driven Networks 2024年4月26-28日 | 中国沈阳 基于前几届在英国埃克塞特 (ISPA 2020) 、中国沈阳 (TrustCom 2021) 和中国武汉 (IEEETrustCom-2022) 成功举…

如何查看Microsoft Office 使用期限

1.进入到 Office 软件的安装目录&#xff08;******\Microsoft Office\Office&#xff09; ## 以管理员身份打开 Windows PowerShell输入以下命令&#xff0c;回车 cscript ospp.vbs /dstatusREMAINING GRACE 一行表示激活剩余天数&#xff08;括号内是换算成的剩余分钟数…

Android实验:绑定service实验

目录 实验目的实验内容实验要求项目结构代码实现代码解释结果展示 实验目的 充分理解Service的作用&#xff0c;与Activity之间的区别&#xff0c;掌握Service的生命周期以及对应函数&#xff0c;了解Service的主线程性质&#xff1b;掌握主线程的界面刷新的设计原则&#xff…

文心一言 VS 讯飞星火 VS chatgpt (148)-- 算法导论12.2 3题

三、用go语言&#xff0c;写出过程 TREE-PREDECESSOR 的伪代码。 文心一言&#xff1a; 以下是使用Go语言编写的TREE-PREDECESSOR函数的伪代码&#xff1a; func TREE-PREDECESSOR(node) { if node.parent ! nil { return node.parent } // 如果节点是根节点&#xff0c…

Centos图形化界面封装OpenStack Ubuntu镜像

目录 背景 环境 搭建kvm环境 安装ubuntu虚机 虚机设置 系统安装 登录虚机 安装cloud-init 安装cloud-utils-growpart 关闭实例 删除细节信息 删除网卡细节 使虚机脱离libvirt纳管 结束与验证 压缩与转移 验证是否能够正常运行 背景 一般的镜像文件在上传OpenSt…

第 374 场 LeetCode 周赛题解

A 找出峰值 枚举 class Solution { public:vector<int> findPeaks(vector<int> &mountain) {int n mountain.size();vector<int> res;for (int i 1; i < n - 1; i)if (mountain[i] > mountain[i - 1] && mountain[i] > mountain[i 1…

登录界面(flex布局练习)

练习&#xff1a;登录界面在我们网页制作的过程中经常遇见&#xff0c;所以请你编写一个界面联系一下&#xff0c;这个可以增加一些动画或者是其他的效果&#xff0c;当然越帅越好。请使用flex或者其他布局练习 例如&#xff1a; 代码 <!DOCTYPE html> <html lang…

SLAM ORB-SLAM2(10)轨迹跟踪过程

SLAM ORB-SLAM2(10)轨迹跟踪过程 1. 总体过程2. ORB 特征点提取2.1. 相机数据处理2.1.1. 单目相机图像处理2.1.2. 双目相机图像处理2.1.3. RGBD相机图像处理2.2. ORB 特征点3. 地图初始化3.1. 坐标形式3.2. 坐标原点3.3. 地图尺度4. 相机位姿初始估计4.1. 关键帧4.2. 运动模型…

文件搜索神器—Everything,结合内网穿透秒变在线搜索神器!

Everythingcpolar搭建在线资料库&#xff0c;实现随时随地访问 文章目录 Everythingcpolar搭建在线资料库&#xff0c;实现随时随地访问前言1.软件安装完成后&#xff0c;打开Everything2.登录cpolar官网 设置空白数据隧道3.将空白数据隧道与本地Everything软件结合起来总结 前…

2 文本分类入门:TextCNN

论文链接&#xff1a;https://arxiv.org/pdf/1408.5882.pdf TextCNN 是一种用于文本分类的卷积神经网络模型。它在卷积神经网络的基础上进行了一些修改&#xff0c;以适应文本数据的特点。 TextCNN 的主要思想是使用一维卷积层来提取文本中的局部特征&#xff0c;并通过池化操…

2023.12.2 关于 Spring AOP 详解

目录 Spring AOP Spring AOP 常见使用场景 AOP 组成 切面&#xff08;类&#xff09; 切点&#xff08;方法&#xff09; 通知 ​编辑 前置通知&#xff08;Before&#xff09; 后置通知&#xff08;After&#xff09; 返回通知&#xff08;AfterReturning&#xff0…

龙芯loongarch64服务器编译安装maturin

前言 maturin 是一个构建和发布基于 Rust 的 Python 包的工具,但是在安装maturin的时候,会出现如下报错:error: cant find Rust compiler 这里记录问题解决过程中遇到的问题: 1、根据错误的提示需要安装Rust Compiler,首先去其官网按照官网给的解决办法提供进行安装 curl…