【Linux】简单设计libc库

📝前言:

经过之间两篇文章,【Linux】基础IO(一)【Linux】基础IO(二)的学些,我们对文件的基础IO已经有了一定的理解。

这篇文章我们来简单设计一下libc库,来复习一下文件基础IO的知识

🎬个人简介:努力学习ing

📋个人专栏:Linux

🎀CSDN主页 愚润求学

🌄其他专栏:C++学习笔记C语言入门基础python入门基础C++刷题专栏


目录

一,综述

目标:用我们的文件实现文件的写入操作

本文主要完成三个文件的编写

  • mystdio.h:头文件,主要用于声明函数,提供接口
  • mystdio.c:源文件,用于实现头文件中声明的函数和全局变量
  • test.c:测试文件

二,Linux内核的_IO_FILE

如图,这就是C库里面,管理文件的结构体

三,mystdio.h的编写

  • C语言库的FILE结构体,就是struct _IO_FILE FILE结构体typedef来的
  • 目标封装:
    • IO_FILE结构体(C语言的结构体),核心参数
      • int flag :文件的刷新方式
      • int fileno:文件描述符
      • char outbuffer[SIZE]:输出缓冲区(语言层)
      • int cap:缓冲区的总容量
      • int size:缓冲区已经使用的字节数
    • myopenmywritemyfflushmyclose操作,模拟C语言里面库函数的调用

实现

cpp 复制代码
  1 #pragma once
  2 
  3 #define MAXSIZE 1024
  4 
  5 #define FLUSH_N 0
  6 #define FLUSH_L 1
  7 #define FLUSH_F 2
  8 
  9 struct IO_FILE
 10 {
 11     int flag;
 12     int fileno;
 13     char outbuffer[MAXSIZE];
 14     int cap;
 15     int size;
 16 };
 17 
 18 typedef struct IO_FILE MYFILE;
 19 
 20 MYFILE* myfopen(const char* pathname, const char* mode);
 21 int myfwrite(const void* ptr, int num, MYFILE* stream); //void* ptr这使得 mfwrite 函数能够接受任意类型的数据缓冲区。                                                                                         
 22 void myfflush(MYFILE* stream);
 23 void myfclose(MYFILE* stream);                      

四,mystdio.c的编写

接口介绍

memcpy

  • 原型:void* memcpy(void* dest, const void* src, size_t n);
    • dest:目标内存区域的起始地址(需确保有足够空间)
    • src:源内存区域的起始地址(只读)
    • n:要复制的字节数(size_t 类型,通常由 sizeof 或手动计算得到)

fsync

  • 传入文件描述符,把对应的内核文件缓冲区刷新到外设(我们不用管如何刷新的,只要知道能刷新就行了)

openclose 等文件的系统调用不过多赘述,如果不懂的可以这篇文章:【Linux】基础IO(一)

实现

cpp 复制代码
  1 #include "mystdio.h"
  2 #include <string.h>
  3 #include <stdlib.h>
  4 #include <sys/stat.h>
  5 #include <sys/types.h>
  6 #include <fcntl.h>
  7 #include <unistd.h>
  8 
  9 MYFILE* myfopen(const char* pathname, const char* mode)
 10 {
 11     // opne时,如果对不存在的文件,那就要创建文件并且初始化FILE结构体
 12     int fd = -1; // 代表 open失败
 13     // 对于不同的打开方式,我们主要通过更新它的 FILE 来体现文件不同的状态
 14     if(strcmp(mode, "r") == 0)
 15     {
 16         fd = open(pathname, O_RDONLY); // 封装系统调用
 17     }
 18     else if(strcmp(mode, "w") == 0)
 19     {
 20         fd = open(pathname, O_CREAT|O_WRONLY|O_TRUNC, 06660);
 21     }
 22     else if(strcmp(mode, "a") == 0)
 23     {
 24         fd = open(pathname, O_CREAT|O_WRONLY|O_APPEND, 06660);
 25     }
 26     if(fd < 0) return NULL; // 代表开失败了
 27     MYFILE* mf = (MYFILE*)malloc(sizeof(MYFILE)); // 申请MYFILE结构体,给新的文件
 28     if(!mf) // 分配失败
 29     {
 30         close(fd);
 31         return NULL;
 32     }
 33     mf -> fileno = fd;
 34     mf -> flag = FLUSH_L; // 我们默认用行刷新,简单一点
 35     mf -> size = 0;
 36     mf -> cap = MAXSIZE;
 37 
 38     return mf;
 39 }
 40 int myfwrite(const void* ptr, int num, MYFILE* stream)
 41 {
 42     // 语言层写到缓冲区,本质是拷贝                                                                                                                                                                          
 43     memcpy(stream->outbuffer + stream->size, ptr, num);
 44     stream -> size += num;
 45     if(stream -> size > 0 && stream -> flag == FLUSH_L && stream -> outbuffer[stream->size - 1] == '\n')
 46     {
 47         myfflush(stream);
 48     }
 49     return num;
 50 }
 51 void myfflush(MYFILE* stream)
 52 {
 53     if(stream->size > 0)
 54     {
 55         write(stream->fileno, stream->outbuffer, stream->size);
 56         // 刷新到外设
 57         fsync(stream->fileno);
 58         stream->size = 0;
 59     }
 60 }
 61 void myfclose(MYFILE* stream)
 62 {
 63     if(stream->size > 0)
 64     {
 65         myfflush(stream);
 66     }
 67     close(stream->fileno);
 68 }
 69 

五,test.c测试

测试往文件log.txt里面写入信息,看是否写入成功

代码:

cpp 复制代码
  1 #include "mystdio.h"
  2 #include <stdio.h>
  3 #include <string.h>
  4 #include <unistd.h>
  5 
  6 int main()
  7 {
  8     MYFILE* fp = myfopen("./log.txt", "a");
  9     if(fp == NULL)
 10     {
 11         printf("打开失败");
 12         return 1;
 13     }
 14     int cnt = 3;                                                                                                                                                                                             
 15     while(cnt)
 16     {
 17         printf("write %d\n", cnt);
 18         char buffer[64];
 19         snprintf(buffer, sizeof(buffer),"hello message, number is : %d\n", cnt);
 20         cnt--;
 21         myfwrite(buffer, strlen(buffer), fp);
 22         myfflush(fp);
 23         sleep(1);
 24     }
 25     myfclose(fp);
 26     return 0;
 27 }

运行结果:


🌈我的分享也就到此结束啦🌈

要是我的分享也能对你的学习起到帮助,那简直是太酷啦!

若有不足,还请大家多多指正,我们一起学习交流!

📢公主,王子:点赞👍→收藏⭐→关注🔍

感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!

相关推荐
tan180°21 分钟前
MySQL表的操作(3)
linux·数据库·c++·vscode·后端·mysql
m0_5557629025 分钟前
Matlab 频谱分析 (Spectral Analysis)
开发语言·matlab
代码老y26 分钟前
Docker:容器化技术的基石与实践指南
运维·docker·容器
巴伦是只猫40 分钟前
【机器学习笔记Ⅰ】13 正则化代价函数
人工智能·笔记·机器学习
典学长编程1 小时前
Linux操作系统从入门到精通!第二天(命令行)
linux·运维·chrome
wuk9981 小时前
基于MATLAB编制的锂离子电池伪二维模型
linux·windows·github
浪裡遊1 小时前
React Hooks全面解析:从基础到高级的实用指南
开发语言·前端·javascript·react.js·node.js·ecmascript·php
彭祥.2 小时前
Jetson边缘计算主板:Ubuntu 环境配置 CUDA 与 cudNN 推理环境 + OpenCV 与 C++ 进行目标分类
c++·opencv·分类
lzb_kkk2 小时前
【C++】C++四种类型转换操作符详解
开发语言·c++·windows·1024程序员节
好开心啊没烦恼2 小时前
Python 数据分析:numpy,说人话,说说数组维度。听故事学知识点怎么这么容易?
开发语言·人工智能·python·数据挖掘·数据分析·numpy