目录
提到文件缓冲区这个概念我们好像并不陌生,但是我们对于这个概念好像又是模糊的存在脑海中,之间我们在介绍c语言文件操作已经简单的提过这个概念,今天我们不妨深入理解什么是文件缓冲区
一、缓冲区图解
二、自定义实现文件操作函数
通过自己实现库中的一些文件操作函数更加深入的理解文件缓冲区
自定义实现的myopen和库里面的open功能大致相同。mywrite和write大致相同。myclose和close大致相同,
通过自定义实现这些系统接口,可以更加深入的了解文件在进行读写的时候系统做了哪些事情。
mystdio.h
1 #pragma once
23 #include<stdio.h>45 #define NUM 10246 #define BUFF_NONE 0x17 #define BUFF_LINE 0x28 #define BUFF_ALL 0x4910typedefstructMY_FILE11{12int fd;13int flags;//flush method 刷新方式14char outputbuffer[NUM];//缓冲区15int current;1617}MY_FILE;1819 MY_FILE*my_fopen(constchar* path,constchar* mode);2021size_tmy_fwrite(constvoid* ptr,size_t size,size_t nmemb,MY_FILE* stream);2223intmy_fflush(MY_FILE* fp);2425intmy_fclose(MY_FILE*fp);
mystdio.c
1 #include "mystdio.h"2 #include<string.h>3 #include<sys/types.h>4 #include<sys/stat.h>5 #include<fcntl.h>6 #include<unistd.h>7 #include<malloc.h>8 #include<assert.h>910//fopen("xxx","a");11 MY_FILE*my_fopen(constchar* path,constchar* mode)12{13//1.识别标志位14int flag=0;15if(strcmp(mode,"r")==0)flag|=O_RDONLY;16elseif(strcmp(mode,"w")==0)flag|=(O_CREAT | O_WRONLY | O_TRUNC);17elseif(strcmp(mode,"a")==0)flag|=(O_CREAT | O_WRONLY | O_APPEND);18else{19//other operator "r+" ,"w+" "a+"20}21//2.尝试打开文件22mode_t m=0666;//文件权限23int fd=0;24if(flag & O_CREAT)fd=open(path,flag,m);25else fd=open(path,flag);2627if(fd<0)returnNULL;//打开文件失败2829//3.给用户返回MY_FILE对象,需要构建30 MY_FILE* mf=(MY_FILE*)malloc(sizeof(MY_FILE));31if(mf==NULL)32{33close(fd);//创建结构体失败,关闭文件,返回NULL 34returnNULL;35}3637//4.初始化MY_FILE对象38 mf->fd = fd;39 mf->flags=0;40 mf->flags |= BUFF_LINE;41memset(mf->outputbuffer,'\0',sizeof(mf->outputbuffer));42 mf->current=0;43//mf->outputbuffer[0]=0; //初始化缓冲区4445//5.返回打开的文件46return mf;47}484950intmy_fflush(MY_FILE* fp)51{52//将用户层缓冲区中的数据,通过系统调用接口,冲刷给OS53assert(fp);54write(fp->fd,fp->outputbuffer,fp->current);55//...56 fp->current=0;57return0;58}60//返回实际写入的字节数61size_tmy_fwrite(constvoid* ptr,size_t size,size_t nmemb,MY_FILE* stream)62{63//1.缓冲区如果已经满了,直接写入 64if(stream->current==NUM)my_fflush(stream);6566//2.根据缓冲区剩余情况,进行数据拷贝67size_t user_size= size*nmemb;//要写入多少数据68size_t my_size=NUM-stream->current;//缓冲区还剩多少空间6970int writen=0;71if(my_size>=user_size)72{73//缓冲区剩余空间可以容纳要写入的数据74memcpy(stream->outputbuffer+stream->current,ptr,user_size);75//3.更新计数器字段76 stream->current += user_size;77 writen=user_size;78}else79{80memcpy(stream->outputbuffer+stream->current,ptr,my_size);81//3.更新计数器字段82 stream->current+=my_size;83 writen=my_size;84}8586//3.开始计划刷新87//不发生刷新的本质就是不进行IO,不进行系统调用,所以my_write函数会调用非常快,数据暂时保存在缓冲区 中88//可以在缓冲区积压多份数据,统一进行刷新 本质:就是一次IO可以IO更多的数据,提高IO效率89if(stream->flags & BUFF_ALL)90{91if(stream->current==NUM)my_fflush(stream);//全缓冲92}elseif(stream->flags & BUFF_LINE)93{94if(stream->outputbuffer[stream->current-1]=='\0')my_fflush(stream);95}else{}96return writen;97}9899100intmy_fclose(MY_FILE*fp)101{102assert(fp);103//1.冲刷缓冲区104if(fp->current>0)105{106my_fflush(fp);107}108//2.关闭文件109close(fp->fd);110//3.释放堆空间111free(fp);112//4.指针置为NULL 113 fp=NULL;114return0;115}
main.c
1 #include"mystdio.h"2 #include<unistd.h>3 #include<string.h>45 #define MYFILE "log.txt"67intmain()8{9 MY_FILE* fp=my_fopen(MYFILE,"w");10if(fp==NULL)return1;111213constchar* msg="hello my write";14int cnt=5;15//操作文件16while(cnt)17{18char buffer[1024];19snprintf(buffer,sizeof(buffer),"%s:%d\n",msg,cnt--);20size_t size=my_fwrite(buffer,strlen(buffer),1,fp);21sleep(1);22printf("当前成功写入%lu个字节\n",size);23}24my_fclose(fp);25return0;26}
运行结果
三、强制刷新内核缓冲区(fsync)
将文件缓冲区的内容强制刷新到文件中。
版权归原作者 Insisting. 所有, 如有侵权,请联系我们删除。