文件描述符
2.1 文件描述符
文件描述符(File Descriptor)是在Unix-like操作系统中用于标识和访问文件或I/O设备的抽象概念。它是一个非负整数,用于**唯一标识一个打开的文件、套接字(socket)或其他类型的I/O资源。**文件描述符是进程级的,每个进程都有它自己的文件描述符表。
使用**文件描述符(file descriptor,简称fd),当在进程中打开一个现有文件或者创建一个新文件时,内核向该进程返回一个文件描述符,用于对应这个打开/新建的文件。**
一些基本的系统调用,比如open
、read
、write
、close
等,使用文件描述符来指定操作的目标。当程序打开一个文件时,系统调用返回一个文件描述符,之后可以使用这个文件描述符进行读写等操作。例如:
#include <fcntl.h>
int file_descriptor = open("example.txt", O_RDONLY);
上述代码中,open
函数打开一个文件(“example.txt”),并返回一个文件描述符(file_descriptor
),以后可以使用这个文件描述符进行读取操作。
2.2 文件描述符表
虚拟地址空间的内核区有专门用于进程管理的模块, Linux的进程控制块PCB(process control block)本质是一个叫做task_struct的结构体,里边包括管理进程所需的各种信息,其中有一个结构体叫做file ,我们将它叫做文件描述符表,里边有一个整形索引表,用于存储文件描述符。
内核为每一个进程维护了一个文件描述符表,索引表中的值都是从0开始的,所以在不同的进程中你会看到相同的文件描述符,但是它们指向的不一定是同一个磁盘文件。
- 打开的最大文件数
每一个进程对应的文件描述符表能够存储的打开的文件数是有限制的, 默认为1024个,这个默认值是可以修改的,支持打开的最大文件数据取决于操作系统的硬件配置。
- 默认分配的文件描述符
当一个进程被启动之后,内核PCB的文件描述符表中就已经分配了三个文件描述符
- STDIN_FILENO:标准输入,可以通过这个文件描述符将数据输入到终端文件中,宏值为0。
- STDOUT_FILENO:标准输出,可以通过这个文件描述符将数据通过终端输出出来,宏值为1。
- STDERR_FILENO:标准错误,可以通过这个文件描述符将错误信息通过终端输出出来,宏值为2。
- 后续分配
-
因为进程启动之后,文件描述符表中的0,1,2就被分配出去了,因此从3开始分配
-
在进程中每打开一个文件,就会给这个文件分配一个新的文件描述符,比如:
-
通过open()函数打开 /hello.txt,文件描述符 3 被分配给了这个文件,保持这个打开状态,再次通过open()函数打开 /hello.txt,文件描述符 4 被分配给了这个文件,也就是说一个进程中不同的文件描述符打开的磁盘文件可能是同一个。
-
通过open()函数打开 /hello.txt,文件描述符 3 被分配给了这个文件,将打开的文件关闭,此时文件描述符3就被释放了。再次通过open()函数打开 /hello.txt,文件描述符 3 被分配给了这个文件,也就是说打开的新文件会关联文件描述符表中最小的没有被占用的文件描述符。
-
小结:
- 每个进程对应的文件描述符表默认支持打开的最大文件数为 1024,可以修改
- 每个进程的文件描述符表中都已经默认分配了三个文件描述符,对应的都是当前终端文件(/dev/tty)
- 每打开新的文件,内核会从进程的文件描述符表中找到一个空闲的没有别占用的文件描述符与其进行关联
- 文件描述符表中不同的文件描述符可以对应同一个磁盘文件
- 每个进程文件描述符表中的文件描述符值是唯一的,不会重复