什么是缓冲区???

欢迎拜访羑悻的小杀马特.-CSDN博客

本篇主题:什么是缓冲区

制作日期:2024.12.11

隶属专栏:linux之旅

目录

一概念:

二·缓冲类型:

三·所谓的FILE:

四·简单实现libc库:


一概念:

对应在内存中预留的一段空间;用来缓冲输入或者输出的数据;也就是对应的输入缓冲区和输出缓冲区。

那么为什么要引入缓冲区:

每一次对文件进行的读写操作都需要执⾏⼀次系统调 ⽤,执⾏⼀次系统调⽤将涉及到CPU状态的切换,即从⽤⼾空间切换到内核空间,实现进程上下⽂的 切换,这将损耗⼀定的CPU时间,频繁的磁盘访问对程序的执⾏效率造成很⼤的影响。

如果加上了缓冲区,那么就减少磁盘的读写次数, 再加上计算机对缓冲区的操作⼤ 快于对磁盘的操作,故应⽤缓冲区可⼤ 提⾼计算机的运⾏速度。

二·缓冲类型:

什么时候刷新:

1.用户强制刷新(fflush后)。

2·满足刷新条件(也就是后面三种缓冲区对应满足的条件)。

3.进程退出。

三种缓冲区类型:

①全缓冲区:当都写满了后;自动刷新到,之后调用系统的IO操作;如磁盘上普通文件的操作。

②行缓冲区:遇到换行符进行刷新;也就是对应的终端操作:显示器输入输出等就是行刷新;默认⾏缓冲区的⼤⼩为1024。

③无缓冲区:标准I/O库不对字符进⾏缓存,直接调⽤系统调⽤,如标准出错流stderr通 常是不带缓冲区的,这使得出错信息能够尽快地显⽰出来。

下面由一张图展示IO库和和系统之间进行文件操作的关系:

三·所谓的FILE:

c语言的一个文件指针类型;其实是一个结构体;它封装了系统调用需要的fd;以及里面还封装了一个自己的缓冲区。

大致结构:

后面我们会模拟实现一个简单的版本。

下面展示一段代码:

第一次执行(直接运行):

第二次执行:

四·简单实现libc库:

下面我们简单的围绕缓冲区这个概念;利用我们上面所设计的知识简单实现一个模拟c库封装的用户级别的文件操作:

模拟实现相关接口函数:mfopen,mfclose,mfflush,mfwrite

涉及知识:缓冲区,FILE结构体,语言层封装的系统层IO操作。

采用语言:c语言。

我们所谓的FILE其实就是typedef出来的:

这里可以理解为,每次我们利用语言层封装的fopen打开的一个文件类型不就是FILE*;也就是创造了一个这个类型结构体对象。

下面我们来实现上面所说的函数:

mystio.h:

复制代码
#pragma once
#define SIZE 1024
#define FLUSH_NONE 0
#define FLUSH_LINE 1
#define FLUSH_FULL 2
struct IO_FILE
{
 int fla; //文件访问方式
int fileno; //文件描述符
 char outbuffer[SIZE];//缓冲区
 int cap;//最大容量
 int size;//当前尺寸
 int flus;//刷新方式
 };
typedef struct IO_FILE mFILE;

struct IO_FILE*mfopen(const char *filename, const char *mode);
int mfwrite(const void *ptr, int num, mFILE *stream);
void mfflush(mFILE *stream);
void mfclose(mFILE *stream);

mystio.c:

复制代码
#include"mystio.h"
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>

mFILE* buyf(int fileno,int flag){
    mFILE*f=(mFILE*)malloc(sizeof(mFILE));
    if(f == NULL) return NULL;
    f->fla=flag;
    f->fileno=fileno;
    f->flus=FLUSH_LINE;//默认设置成行刷新
    f->cap=SIZE;
    f->size=0;
    memset(f->outbuffer,0,sizeof(f->outbuffer));
    return f;
}
mFILE *mfopen(const char *filename,const char *mode){
    umask(0);
    int fd=-1;
    int flag=0;
    if(strcmp(mode,"r")==0){
        flag = O_RDWR;
        fd = open(filename, flag);
    }
    else if(strcmp(mode,"w")==0){
        flag = O_CREAT | O_WRONLY | O_TRUNC;
        fd = open(filename, flag, 0666);
    }
     else if(strcmp(mode, "a") == 0)
    {
        flag = O_CREAT | O_WRONLY | O_APPEND;
        fd = open(filename, flag, 0666);
    }
    else{}

       if(fd < 0) return NULL;
       return buyf(fd, flag);
}

int mfwrite(const void *ptr, int num, mFILE *stream){
    //依靠size每次判断好要写入的位置,要么直接写在后面要么遇到换行符,直接刷新出去
    //这里清空操作直接用覆盖来代替(也就是把size改成0)
  memcpy(stream->outbuffer+stream->size,ptr,num);
   stream->size+=num;
  if(stream->size>0&&stream->flus== FLUSH_LINE&&stream->outbuffer[stream->size-1]=='\n' )
  {
      mfflush(stream);
  }
  return num;
}

void mfflush(mFILE *stream){
    if(stream->size>0){
        write(stream->fileno,stream->outbuffer,stream->size);//写入内核缓冲区
        fsync(stream->fileno);//把内核缓冲区写入磁盘
         stream->size=0;
    }
}


void mfclose(mFILE *stream){
    if(stream->size>0){//关闭前,先看是否用户级缓冲区有数据,先写入内核缓冲区再清空
        mfflush(stream);
        stream->size=0;

    }
    close(stream->fileno);
}

main.c:

复制代码
#include<stdio.h>
#include"mystio.h"
#include <string.h>
#include <unistd.h>
int main()
{
 mFILE *fp = mfopen("log.txt", "a");
 if(fp == NULL)
 {
 return 1;
 }
 int cnt = 5;
 while(cnt)
 {
 printf("write %d\n", cnt);
 char buffer[64];
 snprintf(buffer, sizeof(buffer),"hello message, number is : %d\n", cnt);
 cnt--;
 mfwrite(buffer, strlen(buffer), fp);
 //mfflush(fp);
 sleep(1);
 }
 mfclose(fp);
free(stream);
}

下面我们来测试一下:

测试一(每次mfwrite写入的时候以\n结尾,也就是让它实现行刷新):

测试二(每次写入的时候故意不输入\n,而是手动刷新):

测试三(把手动刷新去掉,让它直接都写入缓冲区;最后等到mfclose关闭后自己检查缓冲区是否存在数据完成刷新):

今天的缓冲区小知识到此为止;希望对大家的对此认识能更加清晰,万分感谢!!!

在这篇文章的结尾,我满心感激。感谢您愿意耐心地读完我的文字,您的阅读如同阳光照亮了我创作的道路,愿我们在文字的世界里继续相伴前行,共享更多的美好与感动。

相关推荐
188号安全攻城狮14 小时前
【PWN】HappyNewYearCTF_8_ret2csu
linux·汇编·安全·网络安全·系统安全
Yana.nice15 小时前
openssl将证书从p7b转换为crt格式
java·linux
AI逐月15 小时前
tmux 常用命令总结:从入门到稳定使用的一篇实战博客
linux·服务器·ssh·php
小白跃升坊16 小时前
基于1Panel的AI运维
linux·运维·人工智能·ai大模型·教学·ai agent
跃渊Yuey16 小时前
【Linux】线程同步与互斥
linux·笔记
舰长11516 小时前
linux 实现文件共享的实现方式比较
linux·服务器·网络
zmjjdank1ng16 小时前
Linux 输出重定向
linux·运维
路由侠内网穿透.17 小时前
本地部署智能家居集成解决方案 ESPHome 并实现外部访问( Linux 版本)
linux·运维·服务器·网络协议·智能家居
VekiSon17 小时前
Linux内核驱动——基础概念与开发环境搭建
linux·运维·服务器·c语言·arm开发
zl_dfq17 小时前
Linux 之 【进程信号】(signal、kill、raise、abort、alarm、Core Dump核心转储机制)
linux