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