【操作系统原理】重定向和文件系统


🎉博主首页: 有趣的中国人

🎉专栏首页: 操作系统原理

🎉其它专栏: C++初阶 | C++进阶 | 初阶数据结构

本文是 Linux 文件系统 + 文件描述符 fd 的一次"底层视角"梳理

open / read / write 一路拆到 fd → struct file → inode → data block

文章目录

    • [一、两种世界:用户态 vs 内核态](#一、两种世界:用户态 vs 内核态)
      • [1️⃣ 用户态看到的世界](#1️⃣ 用户态看到的世界)
      • [2️⃣ 内核态真正发生的事](#2️⃣ 内核态真正发生的事)
    • [二、文件描述符 fd 是怎么来的?](#二、文件描述符 fd 是怎么来的?)
      • [1️⃣ 每个进程都有一张 fd 表](#1️⃣ 每个进程都有一张 fd 表)
      • [2️⃣ struct file 描述的是"一次打开"](#2️⃣ struct file 描述的是“一次打开”)
    • [三、open 系统调用发生了什么?](#三、open 系统调用发生了什么?)
      • [1️⃣ 创建 struct file](#1️⃣ 创建 struct file)
      • [2️⃣ 分配 fd](#2️⃣ 分配 fd)
      • [3️⃣ 返回 fd](#3️⃣ 返回 fd)
    • [四、为什么 fd 一定是"最小可用值"?](#四、为什么 fd 一定是“最小可用值”?)
    • [五、0 / 1 / 2 是怎么来的?](#五、0 / 1 / 2 是怎么来的?)
      • [shell 重定向的本质](#shell 重定向的本质)
    • [六、C 语言缓冲区存在的原因](#六、C 语言缓冲区存在的原因)
      • [为什么 `printf` 不等于 `write`?](#为什么 printf 不等于 write?)
    • 七、文件系统的真实结构(磁盘视角)
      • [一个分区的布局(ext 系)](#一个分区的布局(ext 系))
      • [inode 里有什么?](#inode 里有什么?)
      • 目录的本质
    • 八、路径解析全过程(重点)
    • [九、创建 / 删除文件的本质](#九、创建 / 删除文件的本质)
    • 十、总结

一、两种世界:用户态 vs 内核态

1️⃣ 用户态看到的世界

在用户看来,文件操作非常简单:

c 复制代码
int fd = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC, 0664);
write(fd, "hello\n", 6);
close(fd);

我们只关心三件事:

  • open 返回一个 整数 fd
  • read / write 对 fd 操作
  • close 释放

fd 并不是真正的文件,它只是一个"索引"。


2️⃣ 内核态真正发生的事

内核内部,真正的链路是:

text 复制代码
fd
 ↓
当前进程 task_struct
 ↓
files_struct
 ↓
fd_array[fd]
 ↓
struct file
 ↓
file_operations -> read / write
 ↓
VFS
 ↓
具体文件系统 / 设备驱动
 ↓
磁盘 / 终端 / socket

一句话总结:

fd 是进程私有的下标,struct file 才是内核中的"打开文件对象"


二、文件描述符 fd 是怎么来的?

1️⃣ 每个进程都有一张 fd 表

task_struct 中:

c 复制代码
struct files_struct {
    struct file *fd_array[NR_OPEN_DEFAULT];
};
  • fd_array[0] → stdin
  • fd_array[1] → stdout
  • fd_array[2] → stderr

👉 fd 本质就是 fd_array 的下标


2️⃣ struct file 描述的是"一次打开"

c 复制代码
struct file {
    struct file_operations *f_op;
    loff_t  f_pos;      // 当前偏移
    int     f_flags;    // 打开方式
    void   *private_data;
};

⚠️ 重要区分:

对象 含义
inode 文件本身(属性、大小、块号)
struct file 某个进程打开它的一次实例

👉 同一个 inode,可以对应多个 struct file


三、open 系统调用发生了什么?

内核大致做三件事:

1️⃣ 创建 struct file

  • 解析路径
  • 找到 inode
  • 填写 f_flags / f_pos
  • 设置 file_operations

2️⃣ 分配 fd

  • 在当前进程的 fd_array 中找最小空槽
  • 例如 3
  • fd_array[3] = struct file*

3️⃣ 返回 fd

text 复制代码
用户拿到的 int fd
其实就是:
fd_array 的下标

四、为什么 fd 一定是"最小可用值"?

因为:

  • fd_array 是一个数组
  • 内核从下标 0 开始扫描
  • 找到第一个空位就用

所以:

c 复制代码
close(1);
int fd = open("a.txt", O_WRONLY);

此时 fd == 1


五、0 / 1 / 2 是怎么来的?

在进程创建时(fork + exec):

  • 内核提前帮你打开好
  • 并放进 fd_array
fd 含义
0 stdin
1 stdout
2 stderr

shell 重定向的本质

bash 复制代码
./a.out > out.log 2>&1

shell 在 exec 之前做的是:

text 复制代码
close(1)
open(out.log) -> fd = 1
dup2(1, 2)

👉 并没有什么"神奇输出"

👉 只是 fd 指向被换了


六、C 语言缓冲区存在的原因

为什么 printf 不等于 write

因为:

  • printf 属于 C 标准库
  • 内部维护 用户态缓冲区
  • 减少系统调用次数

三种缓冲策略:

类型 场景
全缓冲 普通文件
行缓冲 终端
无缓冲 stderr

触发刷新的时机:

  • 缓冲区满
  • 碰到 \n
  • 手动 fflush
  • 进程退出

七、文件系统的真实结构(磁盘视角)

一个分区的布局(ext 系)

text 复制代码
| super block |
| GDT         |
| block bitmap |
| inode bitmap |
| inode table |
| data blocks |

每一块通常是 4KB


inode 里有什么?

  • 文件类型
  • 权限
  • 大小
  • 时间戳
  • 数据块指针

⚠️ inode 不存文件名


目录的本质

目录 = 特殊文件

目录 data block 中存的是:

text 复制代码
文件名 → inode 编号

八、路径解析全过程(重点)

访问 /a/b/c.txt

  1. 从根目录 inode 开始
  2. 在目录 data block 中找 a
  3. 拿到 a 的 inode
  4. 再找 b
  5. 最终找到 c.txt 的 inode
  6. 根据 inode 找 data block

👉 路径解析是逐级 inode + data block 完成的


九、创建 / 删除文件的本质

创建文件(creat / open O_CREAT)

  • 分配 inode(inode bitmap)

  • 分配 data block(block bitmap)

  • 在父目录 data block 中写入:

    text 复制代码
    文件名 → inode

删除文件(unlink)

  • 清 inode bitmap
  • 清 block bitmap
  • 从目录中删除映射关系

⚠️ 如果还有进程持有 struct file:

真正释放会延迟到最后一个引用消失


十、总结

  • fd 是进程私有索引
  • struct file 描述一次打开
  • inode 描述文件本体
  • data block 存内容
  • 目录存"名字 → inode"
  • VFS 用 file_operations 实现多态
  • 重定向 = 换 fd 指向

相关推荐
Trouvaille ~1 天前
【Linux】文件描述符与重定向原理:揭开Linux文件操作的神秘面纱
linux·运维·服务器·开发语言·内核·进程·重定向
列逍4 天前
Linux文件(二)
linux·磁盘·文件系统·挂载·软硬链接·缓冲区
物联网心球6 天前
从ext4文件系统到Linux文件树
linux·linux内核·文件系统
列逍7 天前
Linux文件(一)
linux·文件操作·write·read·重定向·open·文件描述符
边疆.12 天前
【Linux】文件系统
linux·运维·服务器·磁盘·文件系统·软硬链接
J2虾虾12 天前
华为 Obs 的使用
文件系统·华为obs
做人不要太理性15 天前
【Linux系统】ext2文件系统
大数据·linux·操作系统·文件系统
_OP_CHEN15 天前
【Linux系统编程】(十一)从硬件基石到软件中枢:冯诺依曼体系与操作系统深度解析
linux·运维·服务器·操作系统·进程·冯诺依曼体系结构·os
奔跑吧邓邓子19 天前
【C语言实战(72)】C语言文件系统实战:解锁目录与磁盘IO的奥秘
c语言·文件系统·目录·开发实战·磁盘io