提到文件缓冲区这个概念我们好像并不陌生,但是我们对于这个概念好像又是模糊的存在脑海中,之间我们在介绍c语言文件操作已经简单的提过这个概念,今天我们不妨深入理解什么是文件缓冲区。
当我们在程序中写下一条printf语句时,我们希望将这条语句的内容打印到屏幕上。但是如果你将语句放在循环中,难道你执行一次循环那么操作系统就要打印一次这条数据么?答案当然不是
我们对于程序数据和磁盘数据的交换的时候不是直接进行交换的,他们之间存在了一个数据缓冲区,只有缓冲区中的数据达到某种条件时,相应的对象才会对缓冲区中的数据进行操作
下面这段代码很多朋友可能不知道,当你输入一串字符串,假设输入abcdef时,一个回车,你以为接下来要确定输入Y/N时这个代码实际直接结束了,他跳过了输入这个字符的环节(感兴趣的同学试一试)
int main()//验证输入缓冲区 { int ch; char arr[10] = { 0 }; printf("请输入密码\n"); scanf("%s", arr); printf("请确认密码(Y/N)\n"); ch = getchar(); if (ch == 'Y') { printf("y"); } else { printf("n"); } system("pause"); return 0; }为什么呢?让我来告诉你 那我们有没有解决这个bug的方案呢?有,在vs2008下我们可以使用fflush函数来清空输入缓冲区,但是这个函数在高级编译器(vs2013)以后就禁止使用了。但我们可以自己清空缓冲区
while (getchar() != '\n')//在getchar()之前获取完缓冲区中所有的字符 { ; }此代码必须在Linux下验证 如下代码很多同学以为会每秒输出一个a,但是事实上他输出一个后就不在输出了,这其实也就证明输出缓冲区是存在的,只有当缓冲区的数据满时,他才会一次性打印在屏幕上。
int main() { while (1) { printf("a"); Sleep(1);//linux下停止1s } return 0; }我们现在已经证明了确实是有数据缓冲区的存在的,那么数据的缓冲方式到底有哪些呢?
无缓冲:无缓冲的意思是说,直接对数据进行操作,无需经过数据缓冲区缓存,系统调用接口采用此方式行缓存:缓冲区的数据每满一行即对数据进行操作,而通常情况下向屏幕打印数据就是行缓存方式全缓冲:缓冲区的数据满时才对数据进行操作,通常向文件中写数据使用的就是全缓冲方式现在我们来证明这几种数据的缓冲方式:
分别使用printf和write向屏幕打印数据。 想屏幕打印数据:没问题 重定向到文件中:也拿到了我们想要的结果
现在来看看如何证明缓冲区的三种方式
修改代码,给函数的最末尾加了一句fork
打印到屏幕: 重定向到文件:奇怪的现象出现了,文件里居然有两个hello printf
现在我们来说说这两种不同的现象吧:
打印到屏幕:因为write是系统调用函数,无缓冲打印数据,printf是行缓冲打印数据,所以将数据打印到屏幕上再调用fork(其实就是fork没起到作用)是我们预料到的重定向到文件:为什么文件中出现了两次hello printf?首先我们要知道向文件写数据是全缓冲,但是write同样是无缓冲,所以直接写入到文件中,printf打印的数据先被放到了缓冲区中,此时我们调用了子进程,子进程对父进程的数据进行了写时拷贝,对缓冲区中的数据多操作了一次,所以我们发现此时文件中的hello printf就有了两份经过上面的例子,我们实际上还要明白一点,实际上缓冲区这个概念是c语言提供给我们的,我们所调用的系统调用函数其实并不存在缓冲区,缓冲区就是本质上就是一段内存,至于怎么找到这段内存,也就是找到缓冲区,还记得我们描述文件的file结构体么? 也就是说,通过file结构体,我们也就能找到文件相对应的缓冲区了。
