当前位置:首页>Linux>Linux笔记1.2---一切皆文件(下)

Linux笔记1.2---一切皆文件(下)

  • 2026-10-11 06:48:34
Linux笔记1.2---一切皆文件(下)

在上篇Linux笔记1.1---一切皆文件(上):Linux 让所有 I/O 对象对外长得一样(都套同一套接口)。这篇讲内核怎么变出这个外壳、它的边界、以及为什么这么设计。

内核是怎么做到的?——VFS

上篇说「不同对象套了同一个外壳」。这个外壳在内核里叫 VFS(Virtual File System,虚拟文件系统)。

VFS 是内核里的一层翻译官:上层(应用程序)只说「统一的话」(open/read/write),VFS 把这些话翻译成底层各种文件系统/驱动听得懂的指令。

关键的把戏叫 file_operations(操作表):VFS 规定「一个文件对象必须提供这组函数:open/read/write/...」。每种对象(ext4 文件、字符设备、管道)各自实现这组函数,但函数的签名(长什么样)完全一样。

于是 VFS 拿到一个文件对象,就能用同一句 obj->read(...) 调它——根本不管这个 read 背后是「从磁盘扇区读」「从网络包读」还是「内核现编一段数据给你」。

类比:万能遥控器的标准按键(播放/暂停/音量)。电视、音响、投影仪内部实现完全不同,但都按这个面板响应——你按「播放」,它们各自去干各自的事。VFS 就是这个标准按键面板,file_operations 就是「每个设备都得响应这几个键」的约定。

哪些东西其实「不是文件」?

「一切皆文件」是设计理念,不是字面上的绝对规则。有些东西就不是文件:

不是文件的
为什么
CPU
你没法 open("/cpu")——它是调度的对象,不是 I/O 对象
普通物理内存
不通过文件接口访问(mmap 是另一条路,不是 read/write)
进程
进程本身不是文件,但内核把它的信息伪装成/proc/PID 下的文件,让你能 cat 查
信号
发信号用 kill(),不走文件接口
系统调用本身
它是「接口的入口」,不是被访问的对象

注意「进程」那一行——它体现了理念的弹性和分寸:进程本来不是文件,但 Linux 把它的状态映射成 /proc 里的虚拟文件,让你能用熟悉的 cat/grep 去查。这就是「尽可能」三个字:能套文件接口的就套、套了有好处的就套,套不上的不强求。

这套设计带来了什么好处?

这正是 Unix/Linux 能这么灵活的根,也呼应了整个 shell 笔记系列:

  • Shell 能自由组合命令——命令只认 fd(统一接口),A | B | C 里三者互相不知道对方是谁,靠管道(也是文件)连起来。详见 解析执行篇。
  • 重定向几乎适用所有 I/O——cmd > f、cmd > /dev/null、cmd | grep,对象换了行为就变,代码不用改。
  • 工具复用——cat、grep、wc 对任何能当文件读的东西都管用(磁盘文件、/proc、设备…),不用为每种对象写专用工具。
  • 驱动有统一编程模型——写驱动就是实现 file_operations 那组函数,套进 VFS 的壳,用户就能用 open/read 访问你的设备。

一句话:因为接口统一,所以工具通用、命令可组合、行为可替换。

也不是万能的(别神化)

但「一切皆文件」有边界,不是万能药:

  • 网络:早期 socket 确实套进了文件模型,但后来发现 read/write 不够用,socket 有了自己的专用接口(bind/connect/accept)——虽然也用 fd,但接口比文件丰富。
  • 高性能 I/O:io_uring 这种新机制为了性能,不再局限于传统的 read/write 模型。
  • 图形 / GPU:有自己的渲染和计算模型,不是「文件」能简单覆盖的。

这些不是「一切皆文件失败了」,而是任何抽象都有边界——当某个领域的需求超出了「顺序读写」这个模型,就需要专用接口。

真正统一的,是 I/O 模型

最准确的说法是:

Linux 并没有把所有东西都变成磁盘文件,而是尽可能让各种 I/O 对象共享同一套抽象(VFS)和访问方式(open/read/write)。真正统一的不是「文件」,而是「I/O 模型」。

三个关键词收口(也是整篇的骨架):

关键词
对应
统一对象
文件/设备/管道/socket/proc… 都被当成「文件」
统一接口
open/read/write/close
统一思想
解耦「做什么」和「接的是谁」

那么,程序同时打开了一堆「文件」,怎么区分「我现在操作的是哪一个」?答案就是下一篇文件描述符(fd):一个编号,指向你那张私有的接线表。

最新文章

随机文章