浅入缓冲区

简介: 浅入缓冲区

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

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

每一次对文件进行的读写操作都需要执⾏⼀次系统调 ⽤,执⾏⼀次系统调⽤将涉及到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_FILEmfopen(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

include

include

include

include

include

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

include"mystio.h"

include

include

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关闭后自己检查缓冲区是否存在数据完成刷新):

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

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

相关文章
|
6天前
|
存储 缓存 算法
细谈零拷贝
本文探讨了文件传输功能的实现及其性能优化方法。传统方式通过用户缓冲区分块读写文件,存在大量内存拷贝与上下文切换问题,导致性能低下。零拷贝技术通过减少内存拷贝次数和上下文切换,大幅提升文件传输效率,尤其适用于小文件场景。同时,文章分析了PageCache的作用与局限性,指出在大文件传输时,异步IO+直接IO可避免PageCache带来的额外开销。最后总结,零拷贝适合小文件传输,而大文件场景推荐使用异步IO与直接IO结合的方式。
进程间通信——内存映射原理及详解(附有案例代码)
进程间通信——内存映射原理及详解(附有案例代码)
|
设计模式 存储 算法
【c++】:“无敌的适配器来咯“栈和队列模拟实现以及优先级队列的模拟实现。
【c++】:“无敌的适配器来咯“栈和队列模拟实现以及优先级队列的模拟实现。
76 0
|
存储 小程序 编译器
【C/C++】庖丁解牛 深究数据在内存中如何存储
【C/C++】庖丁解牛 深究数据在内存中如何存储
211 0
|
存储 C语言 C++
【C/C++】庖丁解牛 指针的高端操作(上)
【C/C++】庖丁解牛 指针的高端操作
171 0
|
存储 C++
【C/C++】庖丁解牛 指针的高端操作(下)
【C/C++】庖丁解牛 指针的高端操作(下)
110 0
|
数据处理
万能的FIFO篇
万能的FIFO篇
115 0
|
缓存 网络协议 Linux
C/C++零散知识点汇总之缓冲区
C/C++零散知识点汇总之缓冲区
从指针开始慢慢变强(一)
对于字符指针等的解释
75 0
从指针开始慢慢变强(一)
|
存储 消息中间件 缓存
计算机原理探险系列(五)-- 磁盘存储探秘OS中的进程
计算机原理探险系列(五)-- 磁盘存储探秘OS中的进程
131 0