模拟实现:glibc_1.0-文件操作函数fopen fclose fwrite fflush实现。

@bit::Shadow
✧(≖ ◡ ≖✿

目录

文件与缓冲区的关系

模拟实现

文件属性

文件库函数

fopen()

实现:

文件打开会不会发生缓冲区内存在内容?而需要缓冲区刷新?

fwrite()

fflush()

fclose()


复习必看gitee.com

glibc是Linux中使用最广泛最核心的C语言标准库实现。像: printf malloc open strlen等。

模拟实现:使用open write close核心系统调用来实现fopen fwrite fclose fflush。

文件与缓冲区的关系

输入-缓冲区-文件

采用f系列接口,缓冲区是链接stdin与文件的桥梁。

模拟实现

文件属性

为描述文件属性及库函数的便捷实现,创建以struct IO_FILE类型(MyFile)结构体:

cpp 复制代码
#define MAX
typedef struct IO_FILE
{
    int fileNo;  //fd
    int flag;    //打开模式:O_WRONLY、O_CREAT、O_TRUNC及O_APPEND
    char outBuffer[MAX] //缓冲区字符数组
    int bufferlen;    //outBuffer长度
    int flushMethod;  //刷新方法
}MyFile;

注意:typedef的使用格式,typedef将类型"struct IO_FILE"以"MyFile"替代。

文件库函数

fopen()

原型:

FILE* fopen(const char* pathname, const char* mode);

//pathname:绝对路径/相对路径

//mode:"w" "r" "a"............

实现:
cpp 复制代码
MyFile* MyFopen (const char *pathname, const char* f);

1.明确打开方式以对文件属性调整。

2.☆☆☆BuyFile()以malloc申请空间。

3.返回MyFile。

MyFile* MyFopen(const char* pathname, const char* f):

cpp 复制代码
MyFile* MyFopen (const char *pathname, const char* f)
{
    int fd;
    int flag;
    // 打开方法定位属性:
    if(strcmp(f,"r")==0)
    {
         fd = open(pathname,O_RDONLY);
         flag = O_RDONLY;
    }
    else if(strcmp(f,"w")==0)
    {
         fd = open(pathname, O_WRONLY | O_CREAT | O_TRUNC,0666);
         flag = O_WRONLY | O_CREAT | O_TRUNC;
    }
    else if(strcmp(f,"a")==0)
    {
         fd = open(pathname, O_APPEND | O_CREAT, 0666);
         flag = O_APPEND | O_CREAT;
    }
    else
    {
         printf("该功能未添加\n");
         return NULL;
    }
    if(fd == -1) 
    {
        perror("open failed!!\n");
        return NULL;
    }
         
     MyFile* file = BuyFile(fd, flag, LINE_FLUSH);
     if(file == NULL)
     {
         perror("MyFopen::BuyFile() failed\n");
         return NULL;
     }
     return file;
}

MyFile* BuyFile(int _fileNo, int _flag, _flushMethod):

cpp 复制代码
MyFile* BuyFile(int _fileNo, int _flag, int _flushMethod)
{
    //空间申请!!
    MyFile* newfile=(MyFile*)malloc(sizeof(MyFile));
    if(newfile == NULL) return NULL;

    //memset()初始化好的习惯
    memset(newfile, 0, sizeof(MyFile));
    //文件属性设置:
    newfile->fileNo = _fileNo;
    newfile->flag = _flag;
    newfile->flushMethod = _flushMethod;

    return newfile;
}
文件打开会不会发生缓冲区内存在内容?而需要缓冲区刷新?

缓冲区有内容<--->写入操作与接下来文件打开的要求矛盾。

fwrite()

1.传参数据拷贝到缓冲区。

☆2.写入完成后是否刷新缓冲区取决于文件打开方式flag。

cpp 复制代码
size_t MyFwrite(const void *ptr, size_t size, size_t nmemb, MyFile *stream)
{
    //1.拷贝到缓冲区
    memcpy(stream->outBuffer, ptr, size*nmemb);
    //bufferlen是字节个数还是元素个数?   肯定是字节个数因为写入文件的全部设置为字符
    stream->bufferLen += size*nmemb;
    //ferite的作用是写入到缓冲区还是写到文件内?明显是写入到缓冲区否则fwrite就没用了。

    //要立即刷新缓冲区吗?
    //刷新缓冲区的目的是拷贝缓冲区内容到文件内
    //printf("%d\n",size*nmemb);
    //缓冲区需要刷新的情况:
    if((stream->flag & O_TRUNC || stream->flag & O_APPEND) && \
    stream->outBuffer[stream->bufferLen-1]=='\n')
    {
        printf("缓冲区刷新成功\n");
        MyFflush(stream);
    }
    return nmemb;
}

fflush()

fflush是程序退出/fwrite特定类型后的写入数据操作:

cpp 复制代码
//刷新
int MyFflush(MyFile* stream)
{
    if(stream->bufferLen <= 0) return 0;

    //清除缓冲区内容到文件内
    //操作系统只认fd!!
    write(stream->fileNo,stream->outBuffer,stream->bufferLen);
    stream->bufferLen=0;
    return 0;
}

fclose()

☆☆☆清空资源前必先刷新缓冲区:

cpp 复制代码
//Fclose
int MyFclose(MyFile* stream)
{
    //close退出强制刷新缓冲区
    MyFflush(stream);

    close(stream->fileNo);
    //资源释放
    free(stream);
    return 0;
}

感谢观看

求关注

相关推荐
lly20240612 小时前
Perl 时间日期处理指南
开发语言
Xin_ye1008612 小时前
C# 零基础到精通教程 - 第十四章:异步编程——async/await 详解
开发语言·c#
贵州晓智信息科技12 小时前
Smaller Waterfall 的 Three.js 实现
开发语言·javascript·ecmascript
Kristrina12 小时前
我用C++入门教程,学会了基础编程
开发语言·c++
lcj251112 小时前
string类从编译链接到构造析构,解决多文件重复定义+运算符重载,面试必考!
开发语言·c++·面试·职场和发展
雪度娃娃12 小时前
Asio异步通信——处理粘包问题
网络·c++
圣殿骑士-Khtangc12 小时前
Python列表、字典、集合高阶操作精讲:从基础到工程实战
开发语言·python
糖梨13 小时前
Windows 下 Cursor 变量跳转的 WSL2 + clangd 方案 —— 跨平台 Linux C++ 开发环境搭建踩坑实录
c++·跨平台·wsl·clangd·cursor
Dymc13 小时前
【论文解析】用神经网络给优化器“热身“——面向 UAV-UGV 交接任务的学习加速轨迹规划
人工智能·神经网络·学习