在常见的IO函数中有这样的一些系列,open, read, write, lseek及close。这些IO函数经常被称为不带缓冲的I/O(unbuffered I/O),不带缓冲的是什么意思呢?术语不带缓冲指的是每个read和write都调用了内核的一个系统调用。这些函数在调用的时候系统调用直接进行了磁盘文件的写入操作。那么你会发现如果我的程序出现这样的需求,有很多个连续的对同一个文件进行I/O的操作,你的程序将会不断地进行磁盘操作,这将会是一件很可怕的事情,程序运行的会异常的慢,怎么解决呢?很简单,缓冲呗,我想缓冲这个名词在计算机的世界里你不陌生吧?
所谓的缓冲是指在你对文件进行读取或者改写的时候,系统会为你申请一块内存空间,之后的所有操作都是在此内存空间上面进行操作,当你对该文件的操作结束的时候,或者关闭该文件的句柄的时候,或者你有意刷新缓冲区的时候,系统会将缓冲区的内容一并写至磁盘。这样对比一下之前的unbufferd I/O,磁盘操作相比内存操作要慢得多(你应该知道吧?),所以也称之为高级I/O。那么你可能会问,带缓冲的IO API有哪些呢?罗列一下常见的大概有这些:fopen, fread, fwrite, fclose。这些是标准I/O,也就是在<stdio.h>中声明的API,而上面的那些open...这些是在<unistd.h>下声明的。这下你应该知道STDIN和STDIN_FILENO的区别了吧。层次不一样嘛,一个是unbuffered的,一个是buffered的。(低级与高级的)由于不带缓冲的I/O函数已经不是ISO C的组成部分,所以不建议使用该类函数。
下面是一个有意思的程序,用于测试缓冲I/O和非缓冲I/O的函数区别的。
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(){
int a=8;
int b=1;
char p_str[]={"write to stdout\n"};
pid_t pid;
write(STDOUT_FILENO,p_str,sizeof(p_str)-1);
printf("before fork!\n");
// fflush(stdout);
if(pid=fork()==0){
a++;
b++;
}else{
sleep(2);
}
printf("pid %d :a = %d; b = %d\n",getpid(),a,b);
return 0;
}
在本机器上直接编译运行
输出如下:
write to stdout
before fork!
pid 22040: a=9;b=2
pid 22039: a=9;b=1
如果我将程序的输出重定向到另一个临时文件的话,结果的输入又将如下:
write to stdout
before fork!
pid 22045: a=9;b=2
before fork!
pid 22044: a=8;b=1
解释如下:
1 write是unbuffered,所以在执行fork时,已经输出到stdout中了。
2 直接执行时,stdout和interactive terminal相连接,所以是line buffered。Printf执行后,就被输出到stdout中了。因为字符串以换行符结束。
3 输出重定向执行时,stdout被重定向为文件temp.out。所以是fully buffered。Printf执行后,并没有输出到stdout中。后面执行了fork,输出缓冲区也被拷贝到了child中。在parent,child中,再执行printf时,实际是向输出缓冲区追加内容。当parent或child结束时,输出缓冲区的内容被flush。
至于如何将测试二的输出和测试一的结果一样,我想你应该能够想的到。
这让我想起来陈皓老师的一篇文章大家可以参考一下,一道面试题哟。http://coolshell.cn/articles/7965.html