英国网站域名,网站大全,万州区最新消息,湖州专业做网站文章目录 如何理解缓冲区现象概念:文件缓冲区为什么要有缓冲区缓冲区在哪里 自己封装一个简单的文件接口自主封装目标 代码关于缓冲区强制刷新内核 关于字符串格式化函数printf和scanf函数 如何理解缓冲区 以前写过一个进度条, 有一个输出缓冲区-这个缓冲区在哪里,为什么要… 文章目录 如何理解缓冲区现象概念:文件缓冲区为什么要有缓冲区缓冲区在哪里 自己封装一个简单的文件接口自主封装目标 代码关于缓冲区强制刷新内核 关于字符串格式化函数printf和scanf函数 如何理解缓冲区 以前写过一个进度条, 有一个输出缓冲区-这个缓冲区在哪里,为什么要存在 struct file [缓冲区]中的缓冲区与上面这个缓冲区有关系吗 1.先看现象-提出问题 2.提出文件缓冲区 3.解释问题
现象
int main()
{//C库fprintf(stdout,hello fprintf\n);//系统调用const char* msg hello write\n;write(1,msg,strlen(msg));//这里不用加上\0fork();return 0
}这样可以打印出来
hello fprintf
hello write因为此时都是向显示器打印,是采用行缓冲,所以直接就刷新出来的(见下图中的解释) 但是如果我们重定向:./myfile log.txt 结果不一样了:
hello write
hello fprintf
hello fprintf但是如果不加fork();就不会产生这样的结果. 因为此时是普通文件,采用的刷新策略是全缓冲 所以真正的调用顺序应该是:在fork之前,write就直接打印进文件了,但是fwrite只是写在缓冲区中.在fork之后,fwrite的缓冲区中的文件变成了两份(写时拷贝),由此,会出现打印两次的现象.(下图中有解释)
概念:文件缓冲区 为什么要有缓冲区
可以节省调用者的时间:系统调用也是要花费大量时间的 进程可以继续做自己的事情,最后统一刷新
缓冲区在哪里
在你进行fopen打开文件的时候,会得到一个FILE结构体,缓冲区就在该结构体中 而调用write时,是系统调用,没有缓冲区,会直接刷新出来
自己封装一个简单的文件接口
自主封装
目标
用最简单的方式,呈现出对FILE的理解 特点:实现的是一个demo版本,重在呈现原理
代码
makefile
myfile:main.c myfile.cgcc -o $ $^
.PHONY:clean
clean:rm -f myfilemyfile.h
#pragma once#include stdio.h
#include string.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include malloc.h
#include unistd.h
#include assert.h#define NUM 1024
#define BUFF_NONE 0x1
#define BUFF_LINE 0x2
#define BUFF_ALL 0x4typedef struct MY_FILE
{int fd;char outputbuffer[NUM];int flags; // 刷新方式int current;
} MY_FILE;MY_FILE *my_fopen(const char *path, const char *mode);
size_t my_fwrite(const void *ptr, size_t size, size_t nmemb, MY_FILE *stream);
int my_fclose(MY_FILE *fp);myfile.c
#include myfile.hMY_FILE *my_fopen(const char *path, const char *mode)
{int flags 0;if (strcmp(mode, r) 0)flags | O_RDONLY;else if (strcmp(mode, w) 0)flags | (O_WRONLY | O_CREAT | O_TRUNC);else if (strcmp(mode, a) 0)flags | (O_WRONLY | O_CREAT | O_APPEND);mode_t m 0666;int fd 0;if (flags O_CREAT)fd open(path, flags, m);elsefd open(path, flags);if (fd 0){perror(open error);return NULL;}MY_FILE *mf (MY_FILE *)malloc(sizeof(MY_FILE));if (mf NULL){close(fd);return NULL;}mf-fd fd;mf-flags 0;mf-current 0;mf-flags | BUFF_LINE;// mf-outputbuffer[0] 0;//初始化缓冲区memset(mf-outputbuffer, \0, sizeof(mf-outputbuffer));return mf;
}int my_fflush(MY_FILE *fp)
{assert(fp);// 将用户缓冲区中的数据通过系统调用接口冲刷给OSwrite(fp-fd, fp-outputbuffer, fp-current);fp-current 0;fsync(fp-fd);return 0;
}size_t my_fwrite(const void *ptr, size_t size, size_t nmemb, MY_FILE *stream)
{// 1. 缓冲区如果已经满了就直接写入assert(stream);if (stream-current NUM)my_fflush(stream);// 2. 根据缓冲区剩余情况进行数据拷贝即可size_t user_size size * nmemb;size_t my_size NUM - stream-current;size_t writen 0;if (my_size user_size){memcpy(stream-outputbuffer stream-current, ptr, user_size);//3. 更新计数器字段stream-current user_size;writen user_size;}else{memcpy(stream-outputbuffer stream-current, ptr, my_size);//3. 更新计数器字段stream-current my_size;writen my_size;}// 4. 开始计划刷新, 他们高效体现在哪里 -- TODO// 不发生刷新的本质不进行写入就是不进行IO,不进行调用系统调用所以my_fwrite函数调用会非常快,数据会暂时保存在缓冲区中// 可以在缓冲区中积压多份数据统一进行刷新写入本质就是一次IO可以IO更多的数据提高IO效率if (stream-flags BUFF_ALL){if (stream-current NUM)my_fflush(stream);}else if (stream-flags BUFF_LINE){if (stream-outputbuffer[stream-current - 1] \n)my_fflush(stream);}return writen;
}int my_fclose(MY_FILE *fp)
{assert(fp);// 1.关闭文件的时候,C要帮助我们进行冲刷缓冲区if (fp-current 0){my_fflush(fp);}// 2.关闭文件close(fp-fd);// 3.释放堆空间free(fp);// 4.指针置为NULLfp NULL;return 0;
}关于缓冲区
1.历史上我们所谈的缓冲区指的是:用户级缓冲区,语言提供 2.用户层内核-强制刷新内核 强制刷新内核
fsync(fp-fd);关于字符串格式化函数
printf和scanf函数
int my_printf(const char* format,...)
{//1.先获取对应的变量a//2.定义缓冲区,对a转成字符串//2.1 fwrite(stdout,str);//3.将字串拷贝的stdout-buffer即可//4.结合刷新策略显示即可
}完结.