重定向:
在上一期虚拟文件系统中讲到了每个进程在打开后,都会默认打开3个文件,如下:
stdin 标准输入(键盘) 文件描述符:0
stdout 标准输出(显示器)文件描述符:1
stderr 标准错误 文件描述符:2
接下来仔细观察下面代码:
解释:先关闭默认打开的标准输出文件,再打开一个文件命名为log.txt,用c语言的接口printf和fprintf分别向显示器输出数据,刷新一下缓冲区(后面讲),最后关闭fd。
程序运行后,显示器上什么也没打印。
可以发现,原本要打印在显示器上的内容竟然神奇地打印到了文件里!!!为什么???
解释原因:
当一开始关闭标准输出后,文件描述符1就被空了出来,再打开新的文件,新文件被分配的文件描述符就是1,c语言的printf内部实际是往stdout中打印,fprintf也指定了是往stdout中打印,但在c语言中stdout的文件描述符只认1,c语言只认为stdout的文件描述符是1,所以它只往文件描述符为1的文件中打印,所以打印到了文件中!
上述的现象就是一种重定向,所以:
重定向的本质:是在内核中改变文件描述表特定下标的内容,和上层无关!
dup2接口:
接下来介绍一个重定向的重要接口dup2,先查一下手册:
简单来说它的功能就是: 将文件描述符表下标为oldfd的内容拷贝到文件描述符下标为newfd的内存中,我们用dup2来实现一下之前的重定向操作。
运行结果:
因为之前没关1文件,所以它被分配的文件描述符是3,但我们用dup2改变了文件描述符下标为1的内容,将它的内容改为和下标为3的内容一样,做到了重定向;
缓冲区:
在上一篇文件系统中我讲到,linux每个文件都有自己的文件内核级缓冲区,也就是一段内存空间,但它究竟有什么用?
其实在语言层面,对每个文件也有个语言级缓冲区,也称用户级缓冲区。它的主要作用就是,解耦和提高效率。
主要还是提高效率,我举一个简单的例子来帮助理解,我们就是用户,而物流公司其实就是一个巨大的缓冲区,我们要送东西到目的地不用自己跑,提高了用户的效率,但物流公司不会只因为你的一间货物就开始送货,它会等到货满了或者没有新的货物了,才开始送货了,这里提高了刷新IO的效率。
我们在打印数据到显示器时,大概率不会只打印一行,会打印很多数据,我们不可能每次读到一行要打印的数据就调用系统调用接口去打印到文件中,因为调用系统调用是有成本的,每次遇到需要打印的数据就让它进入语言级缓冲区,根据刷新策略来决定什么时候调用系统调用来刷新到内核级缓冲区,再由内核级缓冲区刷新到文件中。
来简单介绍一下几种刷新策略:
1.立刻刷新。
2.行刷新。一般用于显示器,因为要适应用户的阅读习惯。
3.全缓冲。满了才刷新,普通文件
还有特殊情况,当进程退出或者使用fflush接口也可以立刻刷新缓冲区。