目录
四、文件描述符
4.1 文件描述符的内核本质
4.2 文件描述符的分配规则
五、重定向
四、文件描述符
在回忆起上述知识后,那么文件描述符到底是什么呢?
我们不难注意到,刚刚的open接口系统调用接口其实是有返回值的(一个int的整数),其实这个返回值就是文件描述符。同样我们的write接口也用到了文件描述符,根据我们的代码,我们不难发现,当我们通过系统调用进行写文件的操作时,并没有给其传递文件名和路径信息,那么它如何向我们想要写入的文件进行写入的呢? --- 说明肯定有东西指向我们想要写入的文件 --- 这个东西就是我们的文件描述符 --- 那么问题又来了 --- 其为什么能代指一个文件呢? --- 这就需要我们对其在内核的本质进行描述了。
4.1 文件描述符的内核本质
在讲文件描述符怎么来之前,我们先来讲讲文件。
首先可以明确的一点是,如果我们的程序(进程)想要对一个文件进行操作,那么根据冯诺依曼体系结构,其一定要被先加载到内存中来,那么这个时候OS一定需要对其进行管理,如何管理呢?--- 先描述再组织 --- 于是就有了描述文件的内核级别的数据结构。那么这个结构中会有一些什么内容呢?我们用图来了解。
这里面首先有属性我们可以理解,缓冲区我们之后说,那么这个文件的操作方法集是什么呢?有什么作用呢? --- 首先我们可以知道各种硬件设备,根据我们之前的理论中(Linux下一切皆文件),其也是各种文件,那如果我们想要操作不同的硬件设备,是不是要使用不同的读写方法,那如果我们要对每一个文件都维护一个不同名的操作方法,到时候用起来是不是很麻烦,所以我们采取一种不同的策略。
我们采取函数指针的方式,通过指向不同的实现方法,从而达到上层统一的效果,也可以理解为多态。
4.2 文件描述符的分配规则
说了这么多,那么什么是文件描述符依旧还没提到,别急,马上就来了。
我们刚刚了解的只是OS将硬件抽象出来并管理起来的过程,但是还没有交付给我们需要的进程,于是就有了下图
可以看到,这个指针的前三个内容我给其单独空出来了,并没有让其指向我们的磁盘文件等,只是为什么呢? --- 因为当我们允许一个程序时,OS会为我们自动打开三个文件(标准输入,标准输出,标准错误),并且将其放在数组下标0,1,2的位置。
文件描述符的分配规则:在files_struct数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符
也就是说,当我们打开一个新的文件的时候,给的文件描述符不会是0,1,2,除非这期间我们主动关闭了这其中的文件。
五、重定向
我们知道Linux下一切皆文件,所以我们输出的信息,一定是在向文件进行写入,而这个文件是显示器文件,所以我们可以看到写入的信息。而我们又知道,标准输出的文件描述符是1,如果我们通过文件描述符将标准输出关闭,并打开一个新的文件,根据我们的文件描述符分配原则,这个文件的文件描述符将会是1。又因为OS是默认向1号描述符中的文件进行输出的(OS并不关心文件描述符1指向的是不是显示器文件),所以此时我们再进行输出的话,就是相当于向我们指定的文件进行写入,这就是我们的重定向。
这里我们可以写一段代码验证一下,这里我们需要用到一个系统调用去帮助我们完成验证:
这个系统调用的功能是将oldfd给给我们的newfd使得其文件描述符一致,在这里我们可以通过这个系统调用,从而实现我们的重定向。
根据这段代码,我们不难发现,我们应该是要往我们的words.txt中进行写入hello world,接下来让我们验证一下。
很明显,在我们运行程序的时候,原本应该直接打印在屏幕上的hello world被写入到了words.txt中,这也证实了我们刚刚所了解到的,那么输入重定向和追加重定向就交给大家自行尝试啦。