0%

linux中的file对象

Linux 中的 file 对象:进程视角下的已打开文件

在 Linux 系统中,file 对象(文件对象)是进程与文件交互的核心接口,代表进程已打开的文件实例。它与 inode、dentry 共同构成了文件操作的底层框架,但 file 对象更贴近进程的操作视角,记录了进程访问文件的动态状态。

file 对象的本质与核心作用

什么是 file 对象?

file 对象是 Linux 内核在内存中创建的一种数据结构,由 open() 系统调用生成,随 close() 系统调用销毁。它仅存在于进程的上下文中,代表进程对某个文件的 “打开实例”,记录了该进程访问文件的具体方式和状态。

核心功能

  • 跟踪进程对文件的当前偏移量(读写位置);
  • 记录文件的打开模式(如只读 O_RDONLY、读写 O_RDWR、追加 O_APPEND 等);
  • 关联文件的底层元数据(通过指向 dentry 和 inode,间接关联文件的物理信息);
  • 实现文件描述符(fd)与实际文件的映射(进程通过 fd 操作 file 对象)。

file 对象与其他文件系统对象的关系

file 对象、dentry(目录项)、inode(索引节点)是 VFS(虚拟文件系统)的三大核心对象,三者的关系如下:

对象类型 本质 核心关联 唯一性特征
file 进程打开的文件实例 通过 f_path.dentry 指向 dentry 同一文件可被多个进程打开,对应多个 file 对象
dentry 文件名与 inode 的映射 通过 d_inode 指向 inode 同一文件的硬链接对应多个 dentry,但指向同一 inode
inode 文件的物理元数据 记录文件权限、数据块指针等 唯一标识一个文件(跨进程)

形象比喻

  • inode 是文件的 “身份证”(唯一标识物理文件);
  • dentry 是文件的 “户口本”(记录文件名及家庭关系);
  • file 对象是进程的 “借阅证”(记录某进程如何使用该文件)。

file 对象的核心属性

file 对象包含多个关键成员,决定了进程与文件的交互方式,主要包括:

  1. f_pos:文件当前偏移量(读写位置)
    • 记录进程下次读写文件的起始位置(以字节为单位);
    • 例如,打开文件后默认 f_pos=0(从文件开头开始),执行 read(200)f_pos 变为 200。
  2. f_mode:文件打开模式
    • 包含进程对文件的访问权限(如 O_RDONLY 只读、O_WRONLY 只写、O_RDWR 读写);
    • 以及特殊模式(如 O_APPEND 每次写操作前自动将 f_pos 移至文件尾)。
  3. f_flags:文件状态标志
    • O_NONBLOCK(非阻塞模式,避免 IO 操作阻塞进程)、O_SYNC(写操作同步到磁盘后才返回)等。
  4. f_path:文件路径关联
    • 包含 dentry 指针,通过 f_path.dentry->d_inode 可访问文件的 inode。
  5. f_op:文件操作函数集
    • 指向 file_operations 结构体,包含读写(read/write)、seek(llseek)、关闭(release)等操作的函数指针;
    • 不同文件类型(如普通文件、设备文件、管道)的 f_op 实现不同,体现了 VFS 的抽象能力。

file 对象的生命周期与文件描述符

生命周期

  • 创建:进程调用 open()creat() 时,内核检查文件权限后,创建 file 对象,关联 dentry 和 inode,并返回文件描述符(fd)。
  • 使用:进程通过 fd 调用 read()write()lseek() 等系统调用时,内核通过 fd 找到对应的 file 对象,执行相应操作(如更新 f_pos)。
  • 销毁:进程调用 close() 或进程退出时,内核销毁 file 对象,若该 file 是最后一个引用 inode 的对象,则可能触发 inode 的回收(如硬链接数为 0 时)。

文件描述符(fd)的映射

进程通过文件描述符(一个非负整数,如 0、1、2 分别对应标准输入、输出、错误)操作 file 对象,其映射关系由进程的文件描述符表维护:

  • 每个进程有独立的文件描述符表,表项指向内核中的 file 对象;
  • 不同进程的相同 fd 可指向不同 file 对象(如进程 A 的 fd=3 和进程 B 的 fd=3 可能对应不同文件);
  • 若多个进程打开同一文件,每个进程会获得独立的 file 对象(f_pos 等状态独立),但这些 file 对象指向同一 dentry 和 inode。

示例

1
2
3
4
5
6
7
// 进程 1 打开文件
int fd1 = open("test.txt", O_RDWR); // 内核创建 file1 对象,fd1 映射到 file1

// 进程 2 打开同一文件
int fd2 = open("test.txt", O_RDWR); // 内核创建 file2 对象,fd2 映射到 file2

// file1 和 file2 指向同一 dentry 和 inode,但 f_pos 独立

file 对象的特性与常见场景

1. 同一文件的多个 file 对象

多个进程(或同一进程多次打开)同一文件时,会生成多个 file 对象,其特点:

  • 共享 inode 和 dentry(因此文件内容、权限等元数据一致);
  • 独立的 f_pos(读写位置互不影响,除非使用 O_APPEND 等特殊模式);
  • 独立的打开模式(如进程 A 只读打开,进程 B 可读写打开)。

示例

  • 进程 A 打开 test.txt 后读取前 100 字节,f_pos=100
  • 进程 B 同时打开 test.txt,默认 f_pos=0,读取前 50 字节,f_pos=50
  • 两者操作互不干扰,文件内容的修改会通过 inode 同步。

2. 父子进程的 file 对象继承

  • 进程调用 fork() 创建子进程时,子进程会复制父进程的文件描述符表,指向相同的 file 对象
  • 此时父子进程的 file 对象引用计数(f_count)加 1,共享 f_pos 等状态(对同一文件的读写会相互影响);
  • 任一进程调用 close() 只会减少引用计数,直至计数为 0 时 file 对象才会被销毁。

3. 与文件锁的关系

file 对象是文件锁(如 flock()fcntl() 锁)的载体:

  • 内核通过 file 对象的 f_lock 成员管理对该文件的锁定状态;
  • 同一 file 对象上的锁会限制进程自身的操作,不同 file 对象上的锁(即使指向同一文件)会限制跨进程操作

欢迎关注我的其它发布渠道