Linux中文件描述符与打开文件之间的关系

File Descriptor概述

在 linux 系统中,一切都是文件,文件可分为以下几类:

  1. 普通文件
  2. 目录文件
  3. 链接文件
  4. 设备文件

文件描述符(File Descriptor,简称“fd”,以下均会称之为fd),这是内核为了高效管理已被打开的文件所创建的索引,请注意,fd 只是一个索引。这个索引是一个非负整数(通常是小整数,从0开始数),指向被打开的文件,所有执行 I/O 操作的系统调用都通过文件描述符。

我们常见的文件描述符是 012,分别表示标准输入、标准输出和错误输出。一个进程打开时,这个三个“文件”就也被它打开了,有时候,我们用nohup后台运行程序时,会加上2>&1 >1.log 类似的代码,表示重定向,2>&1 表示将标准错误输出打到标准输出,>1.log 表示将标准输出打到1.log这个文件中,这就完成了日志的重定向。

POSIX标准要求每次打开文件时(含socket)必须使用当前进程中最小可用的文件描述符号码。所以,此时,如果进程再打开一个文件,进程描述符会是3

FD 和打开文件之间的关系

文件描述与打开的文件对应模型如下:

0
0
1
1
......
......
5
5
4
4
3
3
2
2
stdin,标准输入
stdin,标准输入
stdout,标准输出
stdout,标准输出
stdout,错误输出
stdout,错误输出
client.log
client.log
cconfig.toml
cconfig.toml

如上图,一个文件描述符与一个打开文件相对应,同时,不同的文件描述符也会指向同一个文件,如45都指向了config.toml文件。

请注意,相同的文件

  1. 可以被不同的进程打开
  2. 可以在同一个进程中被多次打开

操作系统为每个进程维护了一个文件描述符表,该表的值都从0开始的,所以在不同的进程中会有相同的文件描述符,fd相同,不意味着打开的文件相同,因为每个进程都有自己的表,隔离而独立。

要看到具体信息,需要查看由操作系统内核维护的3个数据结构。

  1. 进程级的文件描述符表
  2. 系统级的打开文件描述符表
  3. 文件系统的i-node表

三个表的关系如下:

FD
FD
文件指针
文件指针
进程 1 的 FD 表
进程 1 的 FD 表
0
0
1
1
2
2
3
3
......
......
FD
FD
文件指针
文件指针
进程 2 的 FD 表
进程 2 的 FD 表
0
0
1
1
2
2
3
3
......
......
FD
FD
文件指针
文件指针
进程 3 的 FD 表
进程 3 的 FD 表
0
0
1
1
2
2
3
3
......
......
偏移量
偏移量
状态标志
状态标志
i-node指针
i-node指针
打开文件表
打开文件表
ID
ID
0
0
......
......
24
24
......
......
37
37
38
38
......
......
文件类型%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22%22%20style%3D%22group%22%20vertex%3D%221%22%20connectable%3D%220%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22330%22%20y%3D%22490%22%20width%3D%22320%22%20height%3D%2230%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%223%22%20value%3D%22......%22%20style%3D%22rounded%3D0%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3B%22%20vertex%3D%221%22%20parent%3D%222%22%3E%3CmxGeometry%20width%3D%2280%22%20height%3D%2230%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%224%22%20value%3D%22%22%20style%3D%22rounded%3D0%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3B%22%20vertex%3D%221%22%20parent%3D%222%22%3E%3CmxGeometry%20x%3D%2280%22%20width%3D%2280%22%20height%3D%2230%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%225%22%20value%3D%22%22%20style%3D%22rounded%3D0%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3B%22%20vertex%3D%221%22%20parent%3D%222%22%3E%3CmxGeometry%20x%3D%22160%22%20width%3D%2280%22%20height%3D%2230%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%226%22%20value%3D%22%22%20style%3D%22rounded%3D0%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3B%22%20vertex%3D%221%22%20parent%3D%222%22%3E%3CmxGeometry%20x%3D%22240%22%20width%3D%2280%22%20height%3D%2230%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E
[Not supported by viewer]
文件锁%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22%22%20style%3D%22group%22%20vertex%3D%221%22%20connectable%3D%220%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22330%22%20y%3D%22490%22%20width%3D%22320%22%20height%3D%2230%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%223%22%20value%3D%22......%22%20style%3D%22rounded%3D0%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3B%22%20vertex%3D%221%22%20parent%3D%222%22%3E%3CmxGeometry%20width%3D%2280%22%20height%3D%2230%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%224%22%20value%3D%22%22%20style%3D%22rounded%3D0%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3B%22%20vertex%3D%221%22%20parent%3D%222%22%3E%3CmxGeometry%20x%3D%2280%22%20width%3D%2280%22%20height%3D%2230%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%225%22%20value%3D%22%22%20style%3D%22rounded%3D0%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3B%22%20vertex%3D%221%22%20parent%3D%222%22%3E%3CmxGeometry%20x%3D%22160%22%20width%3D%2280%22%20height%3D%2230%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%226%22%20value%3D%22%22%20style%3D%22rounded%3D0%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3B%22%20vertex%3D%221%22%20parent%3D%222%22%3E%3CmxGeometry%20x%3D%22240%22%20width%3D%2280%22%20height%3D%2230%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%
[Not supported by viewer]
inode表
inode表

  • 同一进程内,可以有多个fd指向同一个打开的文件,它们可能可以是通过dupdup2等系统调用方法生成的,也可能是对同一个文件进行多次open操作
  • 不同进程间,可以有不同的fd指向了同一个打开的文件,这种情形发生在调用父子进程之间(fork),或当一个进程通过UNIX域套接字将一个打开的文件描述符传递给另一个进程时,还有一种巧合情形是,不同的进程独自去调用open函数打开了同一个文件,此时进程内部的描述符正好分配到与其他进程打开该文件的描述符一样
  • 两个不同的文件描述符,若指向同一个打开文件句柄,将共享同一文件偏移量
  • 文件描述符标志(即,close-on-exec)为进程和文件描述符所私有。对这一标志的修改将不会影响其他文件描述符

inode,索引节点,储存文件的元信息,比如文件的创建者、文件的创建日期、文件的大小等等。

存储的元信息如下

  • 文件的字节数
  • 文件拥有者的 User ID
  • 文件的 Group ID
  • 文件的读、写、执行权限
  • 文件的时间戳,共有三个:ctime指inode上一次变动的时间,mtime指文件内容上一次变动的时间,atime指文件上一次打开的时间
  • 链接数,即有多少文件名指向这个inode
  • 文件数据block的位置

查看 inode信息 stat example.txt