Linux从0到1——模拟实现一部分C库接口【fopen/fwrite/fflush/fclose】

Linux从0到1——模拟实现一部分C库接口


0. 前言


我们模拟实现的函数肯定和C库中的函数有很大差别,这里只是从理解的角度去带大家模拟实现一下。实际C库中的函数会更加复杂。


1. mystdio.h头文件


#pragma once

#define SIZE 4096   // 缓冲区大小
// 刷新策略
#define FLUSH_NONE 1    
#define FLUSH_LINE (1<<1)   // 行刷新
#define FLUSE_ALL (1<<2)    // 全刷新


typedef struct _myFILE
{
    int fileno; // fd
    int flag;   // 刷新策略
    char buffer[SIZE];  // 缓冲区
    int end;    // 使用start和end管理缓冲区,start默认是0
}myFILE;


extern myFILE *my_fopen(const char *path, const char *mode);
extern int my_fwrite(const char *s, int num, myFILE *stream);
extern int my_fflush(myFILE *stream);
extern int my_fclose(myFILE *stream);

目标是模拟实现fopen/fwrite/fflush/fclose这四个接口。


2. mystdio.c文件


#include"mystdio.h"
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<stdlib.h>
#include<unistd.h>

#define DFL_MODE 0666

myFILE *my_fopen(const char *path, const char *mode)
{
    int fd = 0;
    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
    {
        // do nothing
    }

    if (flag & O_CREAT) // 如果选项中有O_CREAT
    {
        fd = open(path, flag, DFL_MODE);
    }
    else
    {
        fd = open(path, flag);
    }

    if (fd < 0)
    {
        errno = 2;  // 2错误码,对应的错误信息是文件找不到
        return NULL;
    }

    myFILE *fp = (myFILE*)malloc(sizeof(myFILE));
    if (!fp)
    {
        errno = 3;
        return NULL;
    }
    
    fp->flag = FLUSH_LINE;  // 默认是行刷新
    fp->end = 0;
    fp->fileno = fd;
    return fp;
}

int my_fwrite(const char *s, int num, myFILE *stream)
{
    // 写入
    memcpy(stream->buffer + stream->end, s, num);
    stream->end += num;

    // 判断是否需要刷新
    if ((stream->flag & FLUSH_LINE) && stream->end > 0 && stream->buffer[stream->end - 1] == '\n')
    {
    	// 必须满足 1. 刷新策略是行缓冲 2. 缓冲区不为空 3. 缓冲区最后一个字符是`\n`才进行缓冲区的行刷新。
        my_fflush(stream);
    }

    return num;
}

int my_fflush(myFILE *stream)
{
    if (stream->end > 0)    // 缓冲区不为空
    {
        write(stream->fileno, stream->buffer, stream->end); // 将数据刷新到操作系统
        // fsync(stream->fileno);  // 内核级别的强制刷新,将数据刷新到存储设备
        stream->end = 0;
    }

    // 缓冲区为空,什么都不做

    return 0;
}

int my_fclose(myFILE *stream)
{
    my_fflush(stream);
    return close(stream->fileno);
}

3. 测试文件main.c


#include"mystdio.h"
#include<stdio.h>
#include<string.h>
#include<unistd.h>

int main()
{
    myFILE *fp = my_fopen("./log.txt", "w");
    if (!fp)
    {
        perror("my_fopen");
        return 1;
    }

    const char *s = "hello world\n";
    int cnt = 5;
    while(cnt--)
    {
        my_fwrite(s, strlen(s), fp);
        sleep(1);
    }

    my_fclose(fp);

    return 0;
}

在这里插入图片描述


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-指短琴长-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值