内核文件对象 与 文件描述符
概要:介绍内核文件对象(Linux 中的 struct file):它的核心属性、生命周期与共享关系,以及它与文件描述符、inode 之间的关系。
1 内核文件对象
在操作系统中,内核文件对象是内核内部用于管理已打开文件状态的核心数据结构。在Linux中,它具体表现为 struct file 结构体(定义于include/linux/fs.h)。每当进程成功打开一个文件(或设备、套接字等)时,内核就会动态创建一个 struct file 实例,并将其与进程的文件描述符关联。
1.1 核心作用与关键属性
内核文件对象代表了一次“打开会话”,它独立于文件本身(inode),主要记录本次打开的上下文信息:
- 文件偏移量:记录当前读写位置(
f_pos)。这是进程私有的,除非文件描述符被复制(如fork、dup)。 - 访问模式:打开时指定的读写权限(只读、只写、读写等)。
- 状态标志:如
O_NONBLOCK(非阻塞)、O_APPEND(追加)、O_SYNC(同步写入)等,这些标志影响后续I/O行为。 - 操作函数集指针:指向
struct file_operations结构体,其中包含针对该具体文件类型(如普通文件、套接字、设备文件)的读写、定位等函数指针。这是实现“一切皆文件”抽象的关键。 - 私有数据指针:供底层文件系统或设备驱动使用,用于存储与本次打开相关的私有信息。
- 引用计数:记录有多少个文件描述符指向它(例如被
dup()复制或跨进程共享)。当引用计数降为0时,内核才会销毁此对象。 - 与文件的关联:通过
struct path等成员,最终关联到文件的 inode。inode是文件的唯一身份标识,存储文件在磁盘上的元数据(权限、大小、数据块位置等)和实际数据。
1.2 生命周期与共享关系
- 创建:在
open()、socket()等系统调用中创建。 - 共享:
- 同一进程内通过
dup()复制的文件描述符共享同一个struct file对象,因此共享文件偏移量和状态标志。 - 父进程通过
fork()创建子进程时,子进程继承的文件描述符也指向同一个struct file对象,引用计数增加。 - 两个进程独立调用
open()打开同一文件,会创建两个独立的struct file对象,但它们最终指向同一个inode。
- 同一进程内通过
- 销毁:当所有关联的文件描述符都被关闭(
close())时,引用计数清零,内核调用清理函数并释放内存。
1.3 图解:文件描述符、内核文件对象与inode的关系
进程A
+------------------+
| 文件描述符表 |
| 0: stdin |
| 1: stdout |
| 2: stderr |
| 3: -------> [struct file A] --f_path--> [inode of /tmp/test.txt]
| | (私有偏移量、标志等) (文件元数据与数据块)
| 4: -------> [struct file B] --f_path--> [inode of socket]
+------------------+
|
进程B | (独立打开)
+------------------+ |
| 文件描述符表 | |
| 3: -------> [struct file C] --f_path--> [同一个inode of /tmp/test.txt]
+------------------+ (另一个私有偏移量、标志等)
说明:
- 进程A的描述符3和进程B的描述符3指向不同的
struct file对象(A和C),因此有各自独立的文件偏移量。 - 但这两个
struct file对象通过各自的f_path关联到同一个inode,即磁盘上的同一个文件。
2 文件描述符
文件描述符是操作系统(特别是类Unix系统)中用于标识和管理已打开资源的一个核心概念。它是一个非负整数,是进程访问文件、管道、套接字、设备等所有I/O资源的统一句柄。
2.1 核心本质:索引而非指针
文件描述符本身是一个数组索引。每个进程都有一个私有的文件描述符表,文件描述符就是这个表的索引号。通过这个索引,操作系统才能在表中找到对应的条目,进而访问到内核中真正的资源管理对象。
2.2 工作原理与三层结构
理解文件描述符需要看三层关系:
- 用户层:文件描述符
- 进程看到的只是一个整数(如
3)。 - 标准输入、输出、错误流固定占用
0、1、2。
- 进程看到的只是一个整数(如
- 内核层:文件描述符表
- 每个进程独有的一张表,是文件描述符到内核文件对象的映射表。
- 当进程打开一个资源时,内核会创建一个
struct file对象来管理它,并在该进程的描述符表中找一个空闲的最小索引号,将两者关联。
- 内核层:内核文件对象与inode
- 内核文件对象:代表一次“打开会话”,包含本次打开的状态,如文件偏移量、访问模式、状态标志等。
- inode:代表文件本身在磁盘上的实体,包含文件的元数据(权限、大小、数据块位置等)和实际数据。
- 多个文件描述符(甚至来自不同进程)可以指向同一个内核文件对象(如通过
fork或dup),而多个内核文件对象可以指向同一个inode(如不同进程独立打开同一个文件)。
留下评论