File Descripter


每个进程启动时,都会默认打开三个文件描述符(File Descripter, FD)
文件描述符是一个非负整数,它是一个索引,进程通过这个索引在内核维护的“打开文件表”中查找对应的文件信息
简单来说:文件描述符是进程和内核之间交互文件的“句柄”或“令牌”

FD的本质与内核数据结构

内核管理打开文件涉及到三个关键的数据结构

  1. 进程级的文件描述符表
    • 每个进程都有一个私有的表
    • 表的索引就是文件描述符(FD)
    • 表中的每一项包含一个指向内核打开文件表中的某个条目的指针
    • 此外,它还包含一些进程级的标志,比如FD_CLOEXEC
  2. 系统级的打开文件表
    • 这是一个全局的表,被所有进程共享
    • 表中的每一项(称为一个file结构体)代表一个被打开的文件,它包含了
      • 文件状态标志:如O_RDONLY(只读)、O_WRONLY(只写)、O_APPEND(追加)等
      • 当前文件偏移量:这是文件读/写操作开始的位置。当使用read()write()时,这个偏移量会自动更新
      • 指向该文件的v-node表的指针
  3. 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, ...)向标准输出写入