📝前言:
经过之间两篇文章,【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
:缓冲区已经使用的字节数
myopen
、mywrite
、myfflush
、myclose
操作,模拟C语言里面库函数的调用
实现
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:
- 传入文件描述符,把对应的内核文件缓冲区刷新到外设(我们不用管如何刷新的,只要知道能刷新就行了)
open、close等文件的系统调用不过多赘述,如果不懂的可以这篇文章:【Linux】基础IO(一)
实现
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
里面写入信息,看是否写入成功
代码:
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 }
运行结果:
🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!