【ArchSummit架构师峰会】探讨数据与人工智能相互驱动的关系>>> 了解详情
写点什么

如何理解“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:121943
用户头像

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

关注

评论

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

又碰到一个奇葩的BUG

艾小仙

全面升级 —— Apache RocketMQ 5.0 SDK 的新面貌

阿里巴巴中间件

云计算 阿里云 RocketMQ 云原生 中间件

龙蜥操作系统将捐赠开放原子开源基金会

OpenAnolis小助手

Linux centos 开源社区 开放原子开源基金会

模块二作业

ks

茜纱窗下夜读书(2021年11月)

美月

#读书

如何用 Flutter开发一个直播应用

声网

flutter 人工智能

如何使用注解优雅的记录操作日志 | 萌新写开源 01

Zhendong

Java GitHub

GitHub多次霸榜,两个月拿下10000+Star,不愧是阿里内部开源的SpringCloud Alibaba笔记

Sakura

Java 编程 架构 面试 计算机

基于 RocketMQ 构建阿里云事件驱动引擎EventBridge

阿里巴巴中间件

阿里云 RocketMQ 云原生 中间件 事件总线

阿里云性能测试服务PTS新面貌 - 压测协议、施压能力全新升级

阿里巴巴中间件

阿里云 中间件 性能测试 SaaS 压测

资产管理系统是管钱的吗?不完全对

低代码小观

企业管理 资产配置 资产管理 管理系统 企业资产

RecyclerView使用GridLayoutManager为什么无法均匀分布?

Changing Lin

11月日更

浅谈DNS递归解析和迭代解析之间的区别

喀拉峻

网络安全

AliRTC 开启视频互动 “零计算” 时代

阿里云视频云

阿里云 音视频 RTC 视频云

如何给企业制定碳排放额度?

石云升

学习笔记 碳中和 11月日更 碳交易

Linux踩过的坑

正向成长

Linux

用户案例|告别传统金融消息架构:Apache Pulsar 在平安证券的实践

Apache Pulsar

Apache Pulsar

客户端稳定性异常检测:函数接口“扫雷”实践

阿里巴巴终端技术

函数式接口 稳定性测试 异常检测 客户端 APP稳定性

Python代码阅读(第54篇):斐波那契数列

Felix

Python 编程 斐波那契 阅读代码 Python初学者

并发编程之深入理解CAS

Fox

CAS 并发’ 11月日更 比较与交换

巩固Java基础,备战来年跳槽——你的薪资自己说了算

Java 编程 程序员 面试 线程

300M的文件,9秒钟下载完成,这款软件真的太离谱!

懒得勤快

JWT、JWS与JWE

喵叔

11月日更

【应用分享】百度超级链助力CFCA建设基于区块链的电子数据存证系统

百度开发者中心

百度 超级链

GitHub标星139K的:“嵌入式Linux系统开发教程”

Java Linux 编程 程序员

专业版再增强 | MSE 无缝兼容 Eureka 协议,性能提升50%

阿里巴巴中间件

阿里云 微服务 云原生 中间件 Eureka

程序员:我熟悉多线程!面试官:都不敢写精通,还敢要26K?

Java 编程 程序员 面试 多线程

7张图揭晓RocketMQ存储设计的精髓

阿里巴巴中间件

阿里云 技术 RocketMQ 中间件 存储

使用 Spring Boot 构建可重用的模拟模块

码语者

Spring Boot Module

优酷小程序优化实战

阿里巴巴终端技术

小程序 ios android 客户端 包大小

golang源码学习--context

en

Context

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