Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现

这篇具有很好参考价值的文章主要介绍了Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一.缓冲区的概念和作用

Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现,Linux学习之路,linux,缓冲区,C语言文件库

二.一个样例

Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现,Linux学习之路,linux,缓冲区,C语言文件库
Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现,Linux学习之路,linux,缓冲区,C语言文件库

三.理解样例

1.样例解释

Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现,Linux学习之路,linux,缓冲区,C语言文件库
Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现,Linux学习之路,linux,缓冲区,C语言文件库

2.什么是刷新?

Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现,Linux学习之路,linux,缓冲区,C语言文件库

四.简易模拟实现C标准库

至此,我们理解了缓冲区的概念和作用,下面我们来简易模拟实现一下C标准库

1.我们要实现的大致框架

我们要实现的是:
Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现,Linux学习之路,linux,缓冲区,C语言文件库

2.mylib.h的实现

1.文件结构体的定义

1.首先要有一个文件结构体:

结构体当中
1.要封装文件描述符fd    设置成员变量fileno
2.用户级缓冲区buffer     大小宏定义为SIZE 4096
3.该文件所对应缓冲区的刷新策略 flag

刷新策略分别宏定义为

#define FLUSH_NONE 1        不刷新
#define FLUSH_LINE (1<<1)   行刷新
#define FLUSH_ALL (1<<2)    全刷新
4.缓冲区中有效数据的个数  end
#define SIZE 4096

#define FLUSH_NONE 1
#define FLUSH_LINE (1<<1)
#define FLUSH_ALL (1<<2)

typedef struct my_file
{
    int fileno;
    char buffer[SIZE];
    int end;//缓冲区中有效数据的个数(也就是最后一个有效数据的下一个位置)
    int flag;//缓冲区的刷新策略
}my_file;

2.myfopen等等函数的声明

Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现,Linux学习之路,linux,缓冲区,C语言文件库

1.myfopen:以mode的方式打开path这个文件

path:文件路径+文件名
mode:打开文件的方式
“r”:只读
“w”:覆盖写
“a”:追加写

2.myfwrite当中:把s字符串中前num个数据写入stream文件中

stream:要往哪个文件当中写入数据,stream是对应文件的结构体指针
s:有数据的字符串
num:要写入的数据个数

3.myfflush:刷新文件缓冲区
4.myfclose:关闭该文件

3.完整mylib.h代码

DFL_MODE : 打开文件的默认权限
Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现,Linux学习之路,linux,缓冲区,C语言文件库

3.myfopen函数的实现

Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现,Linux学习之路,linux,缓冲区,C语言文件库

my_file* myfopen(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_WRONLY | O_CREAT | O_TRUNC);
    }
    else if(strcmp(mode,"a")==0)
    {
        flag |= (O_WRONLY | O_CREAT | O_APPEND);
    }
    if(flag & O_CREAT)
    {
        fd=open(path,flag,DFL_MODE);
    }
    else
    {
        fd=open(path,flag);
    }
    //打开文件失败,设置errno错误码并返回NULL
    if(fd==-1)
    {
        errno=2;
        return NULL;
    }
    //创建文件,设置fp的相应属性
    my_file* fp=(my_file*)malloc(sizeof(my_file));
    if(fp==NULL)
    {
        errno=3;
        return NULL;
    }
    fp->fileno=fd;
    fp->flag=FLUSH_LINE;
    fp->end=0;
    return fp;
}

4.myfwrite函数的实现

Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现,Linux学习之路,linux,缓冲区,C语言文件库

//把s中的数据写入stream中
int myfwrite(const char* s,int num,my_file* stream)
{
    //保存旧的缓冲区的大小
    int pos=stream->end;
    //1.先写入用户级缓冲区
    memcpy(stream->buffer+pos,s,num);
    stream->end += num;//更新缓冲区大小
    
    //刷新策略:按行刷新
    if(stream->flag & FLUSH_LINE)
    {
        //2.判断是否需要刷新缓冲区(判断是否有'\n')
        int flushit=0;
        while(pos < stream->end)
        {
            if((stream->buffer[pos])=='\n')
            {
                flushit=1;
                break;
            }
            pos++;
        }

        if(flushit == 1)
        {
            //3.刷新缓冲区:[0,pos]数据
            write(stream->fileno,stream->buffer,pos+1);
            //4.更新缓冲区 把[pos+1,count)的数据移动到[0,count-pos-2]当中
            //一共移动count-pos-1个数据
            //先求出要移动的最后一个数据的下标
            int count=stream->end;
            memmove(stream->buffer,stream->buffer+pos+1,count-pos-1);
            stream->buffer[count-pos-1]='\0';
            stream->end=count-pos-1;
        }
    }
    return num;
}

5.myfflush函数的实现

Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现,Linux学习之路,linux,缓冲区,C语言文件库

int myfflush(my_file* fp)
{
    if(fp->end > 0)
    {
        write(fp->fileno,fp->buffer,fp->end);
        fp->end=0;
    }
    return 0;
}

6.myfclose函数的实现

Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现,Linux学习之路,linux,缓冲区,C语言文件库

int myfclose(my_file* fp)
{
    myfflush(fp);
    return close(fp->fileno);
}

7.演示

下面我们测试一下
Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现,Linux学习之路,linux,缓冲区,C语言文件库
Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现,Linux学习之路,linux,缓冲区,C语言文件库
Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现,Linux学习之路,linux,缓冲区,C语言文件库
跟我们所预想的一样

8.完整代码

1.mylib.h

#pragma once
#include <stdio.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 SIZE 4096
#define DFL_MODE 0666

#define FLUSH_NONE 1
#define FLUSH_LINE (1<<1)
#define FLUSH_ALL (1<<2)

typedef struct my_file
{
    int fileno;
    char buffer[SIZE];
    int end;//缓冲区中有效数据的个数(也就是最后一个有效数据的下一个位置)
    int flag;//缓冲区的刷新策略
}my_file;

my_file* myfopen(const char* path,const char* mode);

int myfwrite(const char* s,int num,my_file* stream);

int myfflush(my_file* fp);

int myfclose(my_file* fp);

2.mylib.c

#include "mylib.h"

my_file* myfopen(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_WRONLY | O_CREAT | O_TRUNC);
    }
    else if(strcmp(mode,"a")==0)
    {
        flag |= (O_WRONLY | O_CREAT | O_APPEND);
    }
    if(flag & O_CREAT)
    {
        fd=open(path,flag,DFL_MODE);
    }
    else
    {
        fd=open(path,flag);
    }
    //打开文件失败,设置errno错误码并返回NULL
    if(fd==-1)
    {
        errno=2;
        return NULL;
    }
    //创建文件,设置fp的相应属性
    my_file* fp=(my_file*)malloc(sizeof(my_file));
    if(fp==NULL)
    {
        errno=3;
        return NULL;
    }
    fp->fileno=fd;
    fp->flag=FLUSH_LINE;
    fp->end=0;
    return fp;
}


//把s中的数据写入stream中
int myfwrite(const char* s,int num,my_file* stream)
{
    //保存旧的缓冲区的大小
    int pos=stream->end;
    //1.先写入用户级缓冲区
    memcpy(stream->buffer+pos,s,num);
    stream->end += num;//更新缓冲区大小
    
    //刷新策略:按行刷新
    if(stream->flag & FLUSH_LINE)
    {
        //2.判断是否需要刷新缓冲区(判断是否有'\n')
        int flushit=0;
        while(pos < stream->end)
        {
            if((stream->buffer[pos])=='\n')
            {
                flushit=1;
                break;
            }
            pos++;
        }

        if(flushit == 1)
        {
            //3.刷新缓冲区:[0,pos]数据
            write(stream->fileno,stream->buffer,pos+1);
            //4.更新缓冲区 把[pos+1,count)的数据移动到[0,count-pos-2]当中
            //一共移动count-pos-1个数据
            //先求出要移动的最后一个数据的下标
            int count=stream->end;
            memmove(stream->buffer,stream->buffer+pos+1,count-pos-1);
            stream->buffer[count-pos-1]='\0';
            stream->end=count-pos-1;
        }
    }
    return num;
}

int myfflush(my_file* fp)
{
    if(fp->end > 0)
    {
        write(fp->fileno,fp->buffer,fp->end);
        fp->end=0;
    }
    return 0;
}

int myfclose(my_file* fp)
{
    myfflush(fp);
    return close(fp->fileno);
}

3.main.c

#include "mylib.h"
int main()
{
    my_file* fp=myfopen("./log.txt","a");
    if(fp==NULL)
    {
        perror("myfopen fail");
        return 1;
    }
    int cnt=10;
    
    const char* message="abc\ndef";
    while(cnt--)
    {
        mywrite(message,strlen(message),fp);
        sleep(1);
    }
    myfclose(fp);
    return 0;
}

以上就是Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现的全部内容,希望能对大家有所帮助!文章来源地址https://www.toymoban.com/news/detail-838579.html

到了这里,关于Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【玩转Linux】标准io缓冲区的操作

    (꒪ꇴ꒪ ),hello我是 祐言 博客主页:C语言基础,Linux基础,软件配置领域博主🌍 快上🚘,一起学习! 送给读者的一句鸡汤🤔: 集中起来的意志可以击穿顽石! 作者水平很有限,如果发现错误,可在评论区指正,感谢🙏         标准I/O缓冲区是用于提高I/O性能的一种机制,

    2024年02月16日
    浏览(43)
  • 【Linux】理解缓冲区

    我们发现 printf 和 fwrite (库函数)都输出了2次,而 write 只输出了一次(系统调用)。为什么呢?肯定和fork有关! C接口的函数被打印了两次系统接口前后只是打印了一次:和fork函数有关,fork会创建子进程。在创建子进程的时候,数据会被处理成两份,父子进程发生写时拷

    2024年01月23日
    浏览(44)
  • 【看表情包学Linux】文件描述符 | 重定向 Redirection | dup2 函数 | 缓冲区的理解 (Cache)

       🤣  爆笑 教程  👉 《看表情包学Linux》👈   猛戳订阅     🔥 💭 写在前面: 在上一章中,我们已经把 fd 的基本原理搞清楚了。本章我们将开始探索 fd 的应用特征,探索 文件描述符的分配原则。讲解重定向,上一章是如何使用 fflush 把内容变出来的,介绍 dup2 函数,

    2023年04月25日
    浏览(40)
  • Linux之缓冲区的理解

    目录 一、问题引入 二、缓冲区 1、什么是缓冲区 2、刷新策略 3、缓冲区由谁提供 4、重看问题 三、缓冲区的简单实现 我们先来看看下面的代码:我们使用了C语言接口和系统调用接口来进行文件操作。在代码的最后,我们还使用fork函数创建了一个子进程。  代码运行结果如

    2024年02月03日
    浏览(38)
  • 【Linux】基础IO----理解缓冲区

    作者:დ旧言~ 座右铭:松树千年终是朽,槿花一日自为荣。 目标:理解缓冲区 毒鸡汤:有些事情,总是不明白,所以我不会坚持。早安! 专栏选自:Linux初阶 望小伙伴们点赞👍收藏✨加关注哟💕💕 缓冲区大家其实不陌生,像我们使用的 VS2019 编译器这里就有缓冲区,那它

    2024年04月13日
    浏览(33)
  • 用Linux的视角来理解缓冲区概念

    缓冲区(buffer)是存储数据的临时存储区域。当我们用C语言向文件中写入数据时,数据并不会直接的写到文件中,中途还经过了缓冲区,而我们需要对缓冲区的数据进行刷新,那么数据才算写到文件当中。而缓冲区通常是一块内存区域,可以是数组、队列、链表等数据结构。

    2024年01月20日
    浏览(37)
  • 【Linux】文件缓冲区

    提到文件缓冲区这个概念我们好像并不陌生,但是我们对于这个概念好像又是模糊的存在脑海中,之间我们在介绍c语言文件操作已经简单的提过这个概念,今天我们不妨深入理解什么是文件缓冲区 通过自己实现库中的一些文件操作函数更加深入的理解文件缓冲区 自定义实现

    2024年02月10日
    浏览(44)
  • 【Linux】天天直接IO?我说停停,不如试试文件缓冲区

    收录于【Linux】文件系统 专栏 关于文件描述符与文件重定向的相关内容可以移步 文件描述符与重定向操作。 可以到 浅谈文件原理与操作 了解文件操作的系统接口。 目录 系列文章 揭秘C库文件结构体  文件缓冲区 为什么需要文件缓冲区 刷新机制 内核文件缓冲区 模拟实

    2024年02月09日
    浏览(91)
  • 【linux基础I/O(二)】文件系统讲解以及文件缓冲区的概念

    💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:Linux从入门到精通⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学更多操作系统知识   🔝🔝 对于文件来讲,有打开的在内存中 的文件,也有没有打开的在磁盘上 文件,上一篇文章讲解的是前者,本篇 文章将带大家了解后

    2024年01月19日
    浏览(44)
  • 理解缓冲区

    对于这样的代码,首先可以肯定的是 printf 语句先于 sleep 执行,既然如此那么就应该是先打印语句然后进行休眠,下面看看结果: 但这里却是先休眠以后再打印语句,这是因为存在一个叫缓冲区的东西,当我们要向外设写入数据(让显示器显示就是向显示器写入数据)时会将

    2023年04月25日
    浏览(63)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包