深圳企业网站制作流程,昆明建企业网站多少钱,建设安全监督网,网页设计与网站建设课程文章目录 1. 缓冲区现象2. 用户级和系统级缓冲区3. 缓冲区刷新4. 为什么要有缓冲区5. 文件打印的全缓冲6. 模拟实现C语言文件标准库 本章gitee代码仓库#xff1a;重定向、模拟C语言文件标准库 1. 缓冲区现象 我们这里分别调用了4个差不多的函数#xff0c;但是结果是有一定差… 文章目录 1. 缓冲区现象2. 用户级和系统级缓冲区3. 缓冲区刷新4. 为什么要有缓冲区5. 文件打印的全缓冲6. 模拟实现C语言文件标准库 本章gitee代码仓库重定向、模拟C语言文件标准库 1. 缓冲区现象 我们这里分别调用了4个差不多的函数但是结果是有一定差别的这些其实就是因为有缓冲区的存在导致了现象的不同。
2. 用户级和系统级缓冲区
C语言提供访问文件的接口本质上都是对系统提供的接口进行封装。上面的func3函数我们将一号文件描述符关闭之后C接口的内容都没有在显示器上显示而系统接口write不受影响正常显示。
这个就能说明C语言提供的缓冲区并不是系统级别的缓冲区。例如printf、fprintf、fwrite这些库函数都是先将数据写入到C语言提供的缓冲区当中然后再到合适的时候通过write将内容刷新带内核的缓冲区当中。 所以这里close(1)将一号文件描述符关闭之后再想让write写入那就写不进去了而在此之前write自己的内容是直接写入系统缓冲区的所以我们就能看到通过系统调用write写的内容不受影响而C库函数的内容全部都没有被刷新出来。
3. 缓冲区刷新
缓冲区刷新分为三种 无缓冲直接刷新 行缓冲遇到换行符(\n)刷新 一般向显示器打印采用行刷新 全缓冲缓冲区满了之后再刷新 向文件写入一般采用全缓冲
上面的func4因为我们字符串后面都跟上了\n采用的行刷新和func3不一样遇到\n就刷新缓冲区所以内容能够全部刷新出来。
当然在进程退出的时候也会再刷新一次缓冲区。
4. 为什么要有缓冲区 我们现在有很多快递驿站这些驿站就可以理解为缓冲区有了驿站的存在我们寄快递的时候直接将快递放到驿站填好地址信息我们就可以走了就不需要我们自己亲自去将这个东西给对方而拿快递的时候也是有了驿站的存在我们可以选择在自己有空的时候去拿而不是说快递一到我们就得立马去这样就能极大的提高我们的效率。 缓冲区也是如此我们的库函数将内容交给我们的缓冲区后然后再由缓冲区将内容在合适的时候调用系统接口把内容刷新到系统。这样就能够提高用户的效率让C语言函数的接口更快。 fprintf、printf、scanf这些都是叫格式化输入输出接口我们向显示器打印整数1024在我们看来是一个整数其实本质上是字符。先将我们的内容作为一个整体格式化刷新到C的缓冲区然后统一刷到内核当中。 所以有缓冲区的存在也能更好地配合我们的格式化输入输出。
在C语言的文件操作里面是绕不开这个struct FILE结构体的所以里面也封装了缓冲区字段。 例如我们在C语言当中一次性打开了5个文件那么就会有5个对应的缓冲区。 这个FILE是语言层面的语言层面都是属于用户的所以这个缓冲区是属于用户层的 5. 文件打印的全缓冲
有了这些知识我们再来看上面的func2我们在程序退出之前fork创建子进程在显示器上输出的是正常的但是如果我们将内容重定向到文件当中我们发现C库函数的接口都输出了2次。
这是因为向文件打印时刷新方案变成了全缓冲。 当变为全缓冲之后遇到\n就不再刷新。而这里fork创建子进程子进程会将父进程的代码和数据拷贝一份当然这里缓冲区的数据也会拷贝。因为是全缓冲这里的缓冲区里面是有数据的。 我们先来验证一下这个不创建子进程向文件打印 void func2()
{const char *fstrhello fwrite\n;const char *strhello write\n;printf(hello\n);sleep(1);fprintf(stdout,hello fpf\n);sleep(1);fwrite(fstr,strlen(fstr),1,stdout);sleep(1);write(1,str,strlen(str));sleep(3);//fork();
}可以看到这里向文件打印虽然加了\n但并没有刷新而是采用的全缓冲等进程结束之后全部刷新了。 所以这里拷贝的缓冲区进行写时拷贝父进程退出刷新一次子进程退出刷新一次所以我们就能看到C接口的信息会被刷新2次。而我们输出到显示的时候因为是行缓冲每次直接刷新了到子进程的时候缓冲区里面没有数据了所以就输出一次。 6. 模拟实现C语言文件标准库
简易实现
#includeMystdio.h
#includesys/types.h
#includesys/stat.h
#includefcntl.h
#includeunistd.h
#includestdlib.h
#includestring.h
#includeassert.h#define FILE_MODE 0666_FILE * _fopen(const char*filename,const char*flag)
{assert(filename);assert(flag);int f 0;int fd -1;if(strcmp(flag,w) 0){f (O_CREAT|O_WRONLY|O_TRUNC);fd open(filename,f,FILE_MODE);}else if(strcmp(flag,a) 0){f (O_CREAT|O_WRONLY|O_APPEND); fd open(filename,f,FILE_MODE);}else if(strcmp(flag,r) 0){f O_RDONLY;fd open(filename,f);}elsereturn NULL;if(fd -1) return NULL;_FILE*fp (_FILE*)malloc(sizeof(_FILE));fp-fileon fd;fp-flag FLUSH_ALL; fp-out_pos 0; //初始缓冲区没有内容return fp;
}
int _fwrite(_FILE*fp,const char*s,int len)
{memcpy(fp-outbuffer[fp-out_pos],s,len);fp-out_poslen;if(fp-flag FLUSH_NOW){write(fp-fileon,fp-outbuffer,fp-out_pos);fp-out_pos 0;}else if(fp-flagFLUSH_LINE){if(fp-outbuffer[fp-out_pos-1] \n){write(fp-fileon,fp-outbuffer,fp-out_pos);fp-out_pos 0;}}else if(fp-flagFLUSH_ALL){if(fp-out_pos SIZE){write(fp-fileon,fp-outbuffer,fp-out_pos);fp-out_pos 0;} }return len;
}void _fflush(_FILE*fp)
{if(fp-out_pos0){write(fp-fileon,fp-outbuffer,fp-out_pos);fp-out_pos 0;}
}void _fclose(_FILE*fp)
{if(fp NULL) return;_fflush(fp);close(fp-fileon);free(fp);
}