Linux运维|【Linux】浅谈文件描述符和重定向

前言 文件描述符是从0开始增长的整数,对于一个Linux进程而言,默认会打开0、1、2三个文件描述符,也就是打开三个文件

文件描述符 文件
0 标准输入 键盘文件
1 标准输出 显示器文件
2 标准错误 显示器文件
当我们用系统接口open打开新的文件时,新分配的文件描述符是最小的未被分配的
目录
  • 1.进程、文件和文件描述符
  • 2.重定向
1.进程、文件和文件描述符 我们首先要明确这样一个概念:文件位于磁盘上时,当我们要操作文件时,实际上是创建了进程来操作文件
在进程控制块pcb所对应的结构体task_struct中,我们可以找到一个files_struct结构体的指针files,进程用这个结构体来管理自己打开的文件
Linux运维|【Linux】浅谈文件描述符和重定向
文章图片

转到定义:
Linux运维|【Linux】浅谈文件描述符和重定向
文章图片

提起从0开始的整数,大家想到了什么?
数组下标!
我们发现,在files_struct,恰好有一个叫做fd_array的struct file*数组,而struct file 结构体我们一看,正是描述文件属性和方法的结构体:
Linux运维|【Linux】浅谈文件描述符和重定向
文章图片

其中,struct file_operations定义了read、write等方法:
Linux运维|【Linux】浅谈文件描述符和重定向
文章图片

我们可以看到,函数指针是C语言结构体实现面向对象的方式
另外值得一提的是,对于所有文件,不管是显示器文件,键盘文件,还是普通文件,file结构体中的file_operations中提供的函数指针方法看上去都是一样的
可能有人会问了,read一个键盘文件和打开一个网卡文件肯定用的方法不一样啊,怎么调用的都叫read
其实不然,调用read之后,read便会去下层调用具体的文件提供的read的方法,对于网卡来说,就是网卡驱动,驱动中含有具体的网卡的read方法
这样一来,在操作系统层面,所有文件的读取都在OS层被抽象化成了read,操作系统读一切的文件在OS层都是用的file_operations中的read
以函数指针的形式,对底层及虚拟化,屏蔽底层硬件的差异,函数指针指向不同的底层的方法,使得上层就能以同样的视角看待文件,抽象出各个硬件的共性供操作系统直接用函数指针调用方法完成一切皆文件的特性
综上,文件描述符是数组fd_array的下标,每一个数组成员指向了一个文件的属性结构体,从而来管理一个具体的文件
Linux把进程打开的文件抽象成了0、1、2…等文件描述符,通过数组和数组下标的方式对文件进行管理
一图蔽只之:
Linux运维|【Linux】浅谈文件描述符和重定向
文章图片

2.重定向 既然进程根据文件描述符才能找到具体的文件,那么是不是只要我们修改文件描述符与文件的对应关系,就能偷梁换柱了呢?
当然!
我们知道,C语言的printf是向显示器打印,那么在系统层,printf一定是向文件描述符为1的文件进行写入操作
printf始终认为fd == 1 的文件是显示器文件,对,它就是咬准这一点的,对于fd == 1 到底指向什么文件,printf不关心
所以说,根据我们上面的一个规则:
新分配的文件描述符是最小的未被分配的
那么如果我们先关闭1号文件描述符,也就是标准输入
然后再创建并打开一个普通文件 file.txt,给file.txt分配的文件描述符就应该是1
再调用printf(“hello world”)
那么helloworld是打印在屏幕上,还是写入到file.txt里呢?
#include #include #include #include #include int main() { // 关闭1号文件描述符 close(1); // 写的方式打开file.txt int fd = open("file.txt", O_WRONLY|O_CREAT, 0644); // 向1号文件描述符写入 printf("helloworld\n"); // 刷新缓冲区 fflush(stdout); // 关闭文件描述符 close(fd); return 0; }

事实证明,helloworld写入到了file.txt中:
Linux运维|【Linux】浅谈文件描述符和重定向
文章图片

这是什么?
【Linux运维|【Linux】浅谈文件描述符和重定向】重 ! 定 ! 向 !

    推荐阅读