File Descripter
每个进程启动时,都会默认打开三个文件描述符(File Descripter, FD)
文件描述符是一个非负整数,它是一个索引,进程通过这个索引在内核维护的“打开文件表”中查找对应的文件信息
简单来说:文件描述符是进程和内核之间交互文件的“句柄”或“令牌”
FD的本质与内核数据结构
内核管理打开文件涉及到三个关键的数据结构
- 进程级的文件描述符表
- 每个进程都有一个私有的表
- 表的索引就是文件描述符(FD)
- 表中的每一项包含一个指向内核打开文件表中的某个条目的指针
- 此外,它还包含一些进程级的标志,比如
FD_CLOEXEC
- 系统级的打开文件表
- 这是一个全局的表,被所有进程共享
- 表中的每一项(称为一个
file结构体)代表一个被打开的文件,它包含了- 文件状态标志:如
O_RDONLY(只读)、O_WRONLY(只写)、O_APPEND(追加)等 - 当前文件偏移量:这是文件读/写操作开始的位置。当使用
read()或write()时,这个偏移量会自动更新 - 指向该文件的v-node表的指针
- 文件状态标志:如
- v-node表
- 这也是一个全局的表
- v-node(虚拟节点)包含了文件的静态信息,例如
- 文件类型(普通文件、目录、套接字等)
- 文件的inode
- 文件的大小
- 文件的所有者和权限
- 指向文件操作函数的指针(如
read,write)
多个文件描述符(甚至来自不同进程)可以指向同一个“打开文件表”条目。这意味着它们共享文件状态和文件偏移量。这通常是通过
fork()(子进程继承父进程的FD)或dup()系列函数实现的 多个“打开文件表”条目可以指向同一个v-node。这意味着同一个文件被独立打开了多次。每个打开都有自己的文件状态和偏移量,互不干扰
标准文件描述符
| FD | 名称 | 常用缩写 | 默认绑定对象 | 说明 |
|---|---|---|---|---|
| 0 | 标准输入 | stdin | 键盘 | 程序的输入源 |
| 1 | 标准输出 | stdout | 屏幕 | 程序的正常输出 |
| 2 | 标准错误 | stderr | 屏幕 | 程序的错误输出 |
这就是为什么在终端运行命令时,输入来自键盘,结果和错误都显示在屏幕上
内核通过文件描述符表来管理进程打开的文件,0、1、2是固定的下标索引
这就是为什么可以在C语言中用read(0, ...)从标准输入读取,用write(1, ...)向标准输出写入