NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

如何理解“Unix 里一切都是文件”这句话?

  • 2018-08-11
  • 本文字数:3319 字

    阅读完需:约 11 分钟

UNIX 操作系统的设计、用户界面、文化和演变都是建立在它的一套统一的想法和概念上。其中最重要的一点可能是“一切皆文件”,而这个概念被认为是 UNIX 的灵魂之一。

这一关键设计原则提供了一个统一的范式,用于访问各种输入输出资源:文档、目录、磁盘驱动器、CD-ROM、调制解调器、键盘、打印机、显示器、终端,甚至是一些进程间通信和网络通信。所有这些资源拥有一个通用的抽象,UNIX 之父将其称为“文件”。因为每个“文件”都通过相同的 API 暴露出来,所以你可以使用同一组基本命令来读取和写入磁盘、键盘、文档或网络设备。

这个基本概念实际上有双重含义:

  • 在 UNIX 中,一切都是字节流
  • 在 UNIX 中,文件系统是统一的命名空间

在 UNIX 中,一切都是字节流

那么 UNIX 中的文件是由什么组成的?文件只不过是可以读取和写入的普通字节的集合。如果你持有一个文件引用(也就是文件描述符),就可以使用相同的一组 API 进行 IO 操作,无论设备的类型和底层硬件是什么。

纵观历史,UNIX 是第一个对所有 IO 操作进行统一抽象并提供一小组操作原语的操作系统。当时,大多数操作系统为每种设备或设备家族提供单独的 API。一些早期的微型计算机操作系统甚至要求你使用多个用户命令来复制文件——不同大小的软盘需要使用不同的命令!

从程序员和用户的角度来看,UNIX 通过字节流的形式暴露了如下的资源:

存储在磁盘上的文档、目录、链接、大容量存储设备(如磁盘驱动器、CD-ROM、磁带、USB)、进程间通信(例如管道、共享内存、UNIX 套接字)、网络连接、交互式终端、其他设备(如打印机、图形卡)。用户可以对这些字节流进行读(read)、写(write)、随机访问(lseek)和关闭(close)操作。

统一的 API 对于 UNIX 程序来说非常重要:你可以尽情地开发一个处理文件的程序,却不需要知道文件内容究竟是来自哪里,它们可能保存在本地磁盘或网络某处的远程驱动器上,或者是通过网络流入、由用户输入,甚至是由另一个程序在内存中生成。这大大降低了程序的复杂性,并简化了开发人员的学习曲线。这一基本特性让程序开发变得轻而易举(你只需与两个特殊文件打交道:标准输入和标准输出)。

不过需要注意的是,虽然所有文件都提供了统一的 API,但某些特定类型的设备可能不支持某些操作。例如,你无法对鼠标设备进行 lseek 操作,也无法在 CD-ROM 设备上进行 write 操作(假设你的 CD 是只读的)。

在 UNIX 中,文件系统是统一的命名空间

在 UNIX 中,文件不只是具有统一 API 的字节流,还可以通过统一的方式来引用它们:文件系统就是统一的命名空间。

全局命名空间和挂载机制

UNIX 的文件系统路径提供了统一的模式来标记资源,无论其性质如何。例如,你可以使用 /usr/local 引用本地目录,使用 /home/joe/memo.pdf 引用一个文件,使用 /mnt/cdrom 引用 CD-ROM,使用 /usr 引用网络驱动器上的目录,使用 /dev/sda1 引用一个磁盘分区,使用 /tmp/mysql.sock 引用 UNIX 域套接字,使用 /dev/tty0 引用终端,或使用 /dev/mouse 引用鼠标。这个全局命名空间通常被视为文件和目录的层次结构。文件路径可以引用几乎任何东西:文件系统、设备、网络共享或通信通道。

命名空间是分层的,所有资源可以从根目录(/)开始引用。你可以访问同一命名空间内的多个文件系统:只需要将其他设备或文件系统(如外部磁盘驱动器)“附加”到命名空间的某个位置(如 /backups)。在 UNIX 术语中,这个操作叫作挂载(mount)文件系统,而挂载文件系统的位置称为挂载点(mount point)。你可以将挂载文件系统里的所有资源视为全局命名空间的一部分,只要在访问这些资源时使用挂载点作为前缀(例如 /backups/myproject-Oct07.zip)。

挂载机制对于建立统一而连贯的命名空间来说至关重要,在这种命名空间中,异构资源可以重叠。而在微软的操作系统中,MS-DOS 和 Windows 也将设备视为文件,但没有将文件系统视为统一的命名空间。它们的命名空间是分区的,每个物理存储位置都被视为一个不同的实体:C:\是第一个磁盘驱动器,E:\是 CD-ROM 设备,等等。

伪文件系统

在早期,UNIX 通过提供全局 API 并将设备放入统一的文件系统命名空间,极大促进了输入输出资源的集成。这种方法非常成功,以至于越来越多的资源和系统服务被作为文件系统全局命名空间的一部分。Plan 9 操作系统开创了这一壮举,现在已经出现在了所有的现代 UNIX 系统中。

这种方式导致出现了大量的伪文件系统,它们的行为类似于普通文件系统,但可用于访问与传统文件系统不直接相关的资源。例如,你可以使用伪文件系统来查询和控制进程、访问内核或建立 TCP 连接。这些伪文件系统提供了文件系统语义,用于表示结构化的信息,并为各种对象提供统一的访问方式。伪文件系统(有时也称为虚拟文件系统)通常没有实际的物理存储,它们是基于内存的。

伪文件系统示例:

  • procfs(/proc):proc 文件系统包含了一个特殊文件的层次结构,可用于查询或控制正在运行的进程,或通过标准文件条目(主要是基于文本的)来查看内核。
  • devfs(/dev 或 /devices):devfs 将系统上的所有设备显示为一个动态的文件系统命名空间。devfs 还负责管理这个命名空间,并直接与内核设备驱动程序对接,实现智能设备管理——包括注册设备和取消注册。
  • tmpfs(/tmp):临时文件系统,在重新启动后内容就会消失。tmpfs 旨在提高速度和效率,它的文件系统大小是动态的,并使用了交换空间。
  • portalfs(/p):使用 BSD 的 Portal 文件系统,你可以将服务器进程附加到文件系统全局命名空间中,从而通过文件系统来访问网络服务。例如,只需要打开常规文件 /p/tcp/ph7spot.com/smtp,应用程序就可以与托管在 ph7spot.com 上的 SMTP 服务器发生交互。Portal 文件系统有一些神奇之处,因为它在文件系统中提供了套接字语义,可以在标准的 UNIX 工具(如 cat、grep、awk 等)中使用——甚至可以直接用在 Shell 中!
  • ctfs(/system/contract):合约文件系统充当了与 Solaris 合约子系统的接口。Solaris 合约定义了进程或进程组在发生各种类型的事件和故障时的行为——例如如果进程死了,就重启它。Solaris 合约为软件管理和各种环境的监控提供了高级功能,如集群故障恢复系统、批处理队列系统和网格计算引擎。

结论

在现代 UNIX 操作系统中,所有的设备和大多数进程间通信都被视为文件系统层次结构中的文件或伪文件。这种 UNIX 愿景和设计原则被称为“一切皆文件”,是 UNIX 保持成功和长青的关键因素之一。它提供了一个强大而简单的抽象,作为系统、工具和社区的构建基础。更重要的是,它提供了强大的集成和基本的组合机制,通过连接工具和应用程序来解决眼前的问题。

尽管“一切皆文件”的理念取得了成功,但有些人对它的普遍适用性持怀疑态度。如果说文件被视为字节流,那么就会缺少对元数据的支持:为了能够正确地处理文件,应用程序必须使用自己的方法来确定文件的类型、结构和语义。此外,为了保留元数据,处理文件的工具必须保持元数据不变(例如图片的 XMP 信息)。因此,尽管将 UNIX 文件视为字节流对于基于文本接口的程序交互来说非常有用,但在处理多媒体和二进制文件方面却带来了严重的局限性。

尽管存在局限性,但大多数人仍然承认这个理念所具备的强大威力以及它对操作系统集成产生的巨大影响。自 UNIX 首次发布以来,研究人员一直在努力推广这一核心理念。例如,Plan 9 操作系统率先对系统资源采用了完全整合的方法:不仅是设备和通信渠道,所有的系统接口都使用文件系统来表示。例如,Plan 9 的设计者指出,在 UNIX 系统中,网络设备不能完全被视为常规文件:用于访问它们的套接字具有不同的开放语义,并且位于不同的命名空间中(套接字的主机和端口)。Plan 9 的实现证明了我们可以成功地将所有本地和远程设备统一到全局命名空间中。这个概念最终以 portalfs 的形式回到了 UNIX 上。

Plan 9 的其他创新概念建立在“一切皆文件”的原则之上。例如,Plan 9 在统一命名空间的基础上提供了另一层抽象:可以为每个用户或每个进程定制文件系统命名空间,甚至可以动态调整。最后,Plan 9 证明了“一切皆文件”这一理念可以在更大的范围内实现。事实上,这一基本概念在现代 UNIX 操作系统中得到了进一步的扩展。

英文原文: https://ph7spot.com/musings/in-unix-everything-is-a-file

2018-08-11 18:121948
用户头像

发布了 731 篇内容, 共 434.1 次阅读, 收获喜欢 1997 次。

关注

评论

发布
暂无评论
发现更多内容

JavaScript05 - JavaScript数据类型

Mr.Cactus

JavaScript

聚焦目标,团队工作不再一盘散沙(下)

一笑

管理 目标管理 复盘 28天写作

Soul 网关实践 02|选择器&规则介绍

哼干嘛

Java 探索与实践 Soul网关

如何通过即构小程序组件实现直播带货功能?

ZEGO即构

小程序 直播带货

[6/28]产品业务数据分析的质量实践

L3C老司机

日语复习 Day02【~あっての】

IT蜗壳-Tango

程序员 七日更 日语语法

【Mysql-InnoDB 系列】事务提交过程

程序员架构进阶

MySQL 架构 innodb 事务 28天写作

正则表达式匹配ini文件的section

老王同学

区块链介绍

v16629866266

区块链

五种IO模型

懒AI患者

io nio AIo bio IO多路复用

项目管理系列(3)-如何开好一个项目启动会

Ian哥

项目管理 28天写作

创业失败启示录|校园微生活之留学生面对面

阿萌

28天写作 创业失败启示录 青城

想象力,科幻与其他「关于科幻 8/28」

道伟

28天写作

Soul 网关实践 03|http 请求接入网关

哼干嘛

Java 探索与实践 Soul网关

短视频+直播=最自然的表达方式?| 视频号 28 天 (09)

赵新龙

28天写作

智能building之 园区

张老蔫

28天写作

Java 程序经验小结:接口只用于定义类型

后台技术汇

28天写作

精选算法面试-数组III

李孟聊AI

面试 算法 数组 28天写作

低代码是在炒概念,炒得不错

Justin

低代码 28天写作

重学JS | 箭头函数为什么不能用做构造函数?

梁龙先森

面试 大前端 编程语言 28天写作

坚持写作靠什么?

石君

输入 输出 28天写作

胆大无险,脚踏实地

.

28天写作

早上听了一场关于财富的线上专题分享

熊斌

财富自由 28天写作

一文带你学会AQS和并发工具类的关系

比伯

Java 编程 架构 面试 计算机

CMS系统——登录功能

程序员的时光

程序员 七日更 28天写作

28天瞎写的第二百一九天:包辆三轮车上班的日子

树上

28天写作

从硅谷到小米,崔宝秋的25年开源人生

李忠良

28天写作

【计算机内功修炼】六:10张图让你彻底理解回调函数

码农的荒岛求生

异步 同步 异步IO 回调函数 异步编程

读书笔记:《激荡三十年》下

lidaobing

28天写作 激荡三十年

像用户一样测试:别掉链子

QualityFocus

软件测试 用户体验 回归测试

生产环境全链路压测建设历程 29:FAQ 之 评估方法论、改造、痛点

数列科技杨德华

28天写作

如何理解“Unix里一切都是文件”这句话?_语言 & 开发_PH7_InfoQ精选文章