为了有计划的发展架构设计、界面、文化和开发路线,UNIX 系统明确了一系列统一的概念和创想。这几点里面最重要的一点莫过于一句咒语:「一切皆文件」,被广泛认为是 UNIX 的定义之一。

最主要的设计原则是提供一个访问大范围输入/输出资源(包括文件、文件夹、硬盘、CD-ROM、调制解调器、键盘、打印机、显示器、终端机甚至跨进程和网络通讯)的统一的范例。窍门是提供一个所有这些资源的抽象对象,UNIX 之父把这个对象叫做「文件」。因为每个「文件」都由同一个 API[1]暴露,所以你可以用同一套命令来读写/操作磁盘、键盘、文件或网络设备。

这个基本概念有两种含义:

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

在 UNIX 中,一切都是字节流

在 UNIX 中,文件是由什么组成的呢?文件其实和一系列可读写的字节没什么区别。如果你有一个文件的索引(我们称之为「文件描述符[2]」),那么 UNIX 的 I/O 通道就已经准备好了,他们有着同样的一套操作和 API —— 无论设备的类型如何、底层硬件是什么。

纵观历史,UNIX 是第一个把 I/O 抽象成一个统一的概念和一系列原语的系统。那时,大部分操作系统为每一种或一类设备提供不同的 API。一些早期的微型计算机操作系统甚至需要你使用多个命令去拷贝文件 —— 因为每个命令对应指定的软盘大小!

对于大多数程序员和用户来说,UNIX 向他们暴露了:

  • 硬盘中的文件

  • 文件夹

  • 链接

  • 大容量存储设备(例如:硬盘、CD-ROM、磁带、USB 设备)

  • 跨进程通信(例如:管线、共享内存、UNIX 套接字)

  • 网络通信

  • 可交互终端

  • 几乎其他所有设备(例如:打印机、显卡)

对于字节流这种形式你可以:

  • read(读)
  • write(写)
  • lseek(指针移动)
  • close(关闭)

统一的 API 特性对于 UNIX 程序来说是基础也是非常有效的:在 UNIX 中你可以很很轻松地编写一个处理文件的程序,因为不需要关心文件是存储在本地磁盘中、储存在远程网络驱动器上、在互联网中传播、通过用户互动输入,还是通过其他程序在内存中生成。这显著降低了程序的复杂性、减缓了开发者的学习曲线。并且,UNIX 架构的这个基础特性也让程序组合到一起非常简单(你只需要传输两个特殊的文件:标准输入和标准输出)。

最后请注意,当所有的文件提供一致的 API 时,一些特殊类型的设备可能会不支持某些操作。举个很明显的例子,你不可以在鼠标设备上使用 lseek命令,或在 CD-ROM 设备上使用 write命令(假设你的 CD 是只读的)。

文件系统有通用命名空间

在 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 术语来说,这个操作叫做 挂载mounting)一个文件系统,你连接文件系统的命名空间位置叫做 挂载点mount point)。你可以通过给挂载的文件系统中的所有资源添加以挂载点命名的前缀,就像访问通用命名空间的一部分一样,来访问它的所有资源(比如 /backups/myproject-Oct07.zip这个文件)。

当不同的资源会被明显覆盖的情况下,我刚刚描述的挂载机制在建立一个统一的、明确的命名空间时就至关重要。对比一下这种命名空间和微软操作系统中的文件系统命名空间 —— MS-DOS 和 Windows 把设备视为文件但是 不会把文件系统放在通用命名空间中,它的命名空间是分区的并且每个物理存储地址被视为独特的实体[3]C:\是第一个硬盘,E:\是 CD-ROM 设备等等。

伪文件系统

早期,UNIX 因为提供全局 API 以及将设备挂载到统一的文件系统命名空间的特性,大幅提升了输入/输出资源的集成度。这个方法是如此成功,以至于从那时开始有一种将更多资源和系统服务暴露为文件系统全局命名空间的趋势。Plan 9 是这种做法的先驱,而现在所有新的 UNIX 系统都这么做了。

这种方法导致产生了许多 伪文件系统,这些系统看起来和一般的文件系统一样,但是可以存取没有直接关联传统文件系统的资源。比如你可以使用伪文件系统来查询控制进程、存取内核内部或建立 TCP 连接。这些伪文件系统具有文件系统语义,可以展示分层信息,并为大部分对象提供了统一存取的方式。伪文件系统有时也被称为虚拟文件系统,特点是没有物理设备也没有备份存储器,只依靠内存来工作。

伪文件系统的例子:

  • procfs(/proc):proc 文件系统包含一个特殊文件层,这个文件层可以用来查询或控制运行中的进程,或通过标准文件入口(大部分基于文本)一窥内核内部文件。
  • devfs(/devor /devices):devfs 将所有系统中的设备以动态文件系统命名空间呈现。devfs 也可以通过内核设备驱动直接管理这些命名空间和接口,以此来提供智能的设备管理 —— 包括设备入口注册/反注册。
  • tmpfs(/tmp):临时文件系统的内容会在重启时消失,tmpfs 是为速度和效率而设计的,具有动态文件系统大小、用以空间清理的显式回退等特性。
  • portalfs(/p):通过 BSD 门户文件系统,你可以将一个服务器进程连接到文件系统通用命名空间上。这样可以提供明确的通过文件系统对网络服务的存取过程。比如一个 App 可以通过打开一个合规的文件 /p/tcp/ph7spot.com/smtp来和 ph7spot.com上的 SMTP 服务器进行交互。门户文件系统很神奇,因为它在文件系统中可以提供套接字语义,还可以被 UNIX 系统工具传输和使用(比如:catgrepawk等等)—— 甚至可以通过 shell 来使用!
  • ctfs(/system/contract):协定文件系统作为一个以文件为基础的接口的 Solaris 协定子系统。Solaris 协定为各种各样的事件和失败情况定义了一个进程或进程组的表现形式 —— 比如,进程停止时重启。 Solaris 协定为诸如群集故障转移软件,批处理排队系统和网格计算引擎等环境中的软件管理和监视提供了非常高级的功能。

能够通过文件系统语义进行管理的系统资源究竟涉及多么大的范围,上面的例子可以让你对有一个清楚的认识了。

结论

在现代的 UNIX 操作系统中,所有设备和大部分进程间通信在文件系统层级都以文件或伪文件的形式查看和管理。「一切皆文件」的 UNIX 基础愿景和设计原则,是 UNIX 成功和长久的关键因素。它提供了一个有力、简单的抽象,使得系统、工具和社区可以在其之上建立。更重要的是它用一种专有的方式来解决问题,那就是为链接工具和应用提供了强有力的集成和基础组合机制。

尽管「一切皆文件」这个比喻很成功,但是一些人或多或少怀疑它的普遍性。当每个文件都被视为字节流时,产生的一个后果就是元数据缺少标准支持:为了合适地处理一个文件,每个应用必须想办法计算文件类型、架构和语义。并且,为了保存元数据,每个处理数据流的工具必须保持元数据不变(比如照片中的 XMP 信息)。因此,尽管 UNIX 文件的一大堆字节的形态对于链接文字界面的程序极度高效,同时也严重限制了多媒体和二进制应用的组合。

尽管它有它的限制,但很多人也承认这个比喻的影响力,和它在操作系统一体化上的效果。自从 UNIX 第一次发布以来,研究者们持续推进这一中心思想。比如 Plan 9 操作系统倡导一个将系统资源完全集成的方法:Plan 9 愿景的基础就是这样的目标 —— 不仅仅设备和信道,而是将 所有系统接口通过文件系统代表。比如 Plan 9 的设计人员注意到在 UNIX 中,网络设备不能 完全地被视为合格的文件:它们通过套接字存取,而套接字有特有的打开语义并且属于一个不同的命名空间(因特网套接字的主机和端口)。Plan 9 实现并且证明了,你可以在一个全局命名空间里成功的统一所有本地和远程设备。这个想法最终以 portalfs的形式在 UNIX 中实现。

其他来源于 Plan 9 的创新的概念也是基于「UNIX 中,一切皆文件」原则创建的。比如 Plan 9 在统一命名空间设计之上提供了另一个抽象层:文件系统命名空间可以被每个用户、每个进程自定义,甚至动态调整[4]。最后,Plan 9 证明了「UNIX 中,一切皆文件」这个比喻,可以被在更大的层面上实现。事实上,这个基础概念在现代 UNIX 操作系统中正被继续发扬光大[5]

参考文献

  • 一本了不起的书 —— 《The Art of UNIX Programming》,Eric S. Raymond 著。
  • 《The Elements of Operating-System Style》和《Problems in the Design of UNIX》两章对本文有很大帮助。
  • 《10 Things I Hate About (U)NIX》,David Chisnall 著。
  • 「Linux 情报项目」中的挂载定义。
  • Wikipedia 上的 《UNIX File Types》。
  • 《Understanding UNIX Concepts》,USAIL (UNIX System Administration Independent Learning) 著。
  • 《文件系统层级标准》。
  • 《proc 文件系统》,Redhat 出品。
  • 《BSD 系统下的模块化用户模式文件系统》。
  • 《Self-Healing in Modern Operating Systems》,Michael W 著。帮你更深入地理解 Solaris 协议子系统。

作者:Wy_
链接:https://juejin.im/post/5b652d346fb9a04fc03129e6
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

[译] 在 UNIX 中,一切皆文件的更多相关文章

  1. 在linux/unix中查找大文件

    在linux/unix中查找大文件,如查找大于100M文件的位置路径,查找等于10M文件的位置路径等等,下面就介绍几个实现快速查找的命令: 1. 查找指定目录下所有大于100M的文件,命令为 find ...

  2. Linux中一切皆文件

    谈一谈Linux中一切皆文件 1. Linux中所有内容都是以文件的形式保存和管理,即:一切皆文件. 普通文件是文件. 目录(在win下称为文件夹)是文件. 硬件设备(键盘.硬盘.打印机)是文件. 套 ...

  3. unix中文件I/O

    在unix中可用的文件I/O函数包含打开文件,读文件,写文件等. Unix系统中的大多数文件I/O须要用到5个函数:open,read,write,lseek,close. 这里要说明的是read,w ...

  4. 如何理解“Unix 里一切都是文件”这句话-在 UNIX 中,一切都是字节流

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

  5. 今天在Mac机器上使用了Flex Builder编辑了一个源代码文件,保存后使用vim命令去打开时发现系统自动在每一行的结尾添加了^M符号,其实^M在Linux/Unix中是非常常见的,也就是我们在Win中见过的/r回车符号。由于编辑软件的编码问题,某些IDE的编辑器在编辑完文件之后会自动加上这个^M符号。看起来对我们的源代码没有任何影响,其实并不然,当我们把源代码文件Check In到svn之类

    今天在Mac机器上使用了Flex Builder编辑了一个源代码文件,保存后使用vim命令去打开时发现系统自动在每一行的结尾添加了^M符号,其实^M在Linux/Unix中是非常常见的,也就是我们在W ...

  6. [译]在Linux中清空或删除大文件内容的5种方法

    原文来源: https://www.tecmint.com/empty-delete-file-content-linux/ 有时,在处理Linux终端中的文件时,您可能希望清除文件的内容,而无需使用 ...

  7. lsof 一切皆文件

    Docs » 工具参考篇 » 3. lsof 一切皆文件 Docs » 工具参考篇 » 3. lsof 一切皆文件 Edit on GitHub 3. lsof 一切皆文件¶ lsof(list op ...

  8. linux一切皆文件之文件描述符(一)

    一.知识准备 1.在linux中,一切皆为文件,所有不同种类的类型都被抽象成文件.如:普通文件.目录.字符设备.块设备.套接字等 2.当一个文件被进程打开,就会创建一个文件描述符.这时候,文件的路径就 ...

  9. UNIX 环境高级编程 文件和目录

    函数stat , fstat , fstatat , lstat stat函数返回与此文件有关的信息结构. fstat函数使用已打开的文件描述符(而stat则使用文件名) fstatat函数 为一个相 ...

随机推荐

  1. mySql使用手册-官方文档

    https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date-format oracle to_ ...

  2. 65 TCP连接中,流的关闭会造成Socket的关闭

    转自:https://blog.csdn.net/u012525096/article/details/76924627 今天写安卓向服务器发送图片,过程为:客户端发送数据->服务器接收.处理数 ...

  3. sqlalchemy 配合bootstrap-table实现后台分页

    创建公共的mysql连接函数 def db_session(): db_config='mysql+mysqldb://'+ mysqluser + ':' + mysqlpassword+'@'+m ...

  4. TCP/UDP的网络底层实现

    1.1Socket的使用背景 当我们在使用微信.玩游戏.收发邮件,以及用web浏览器上网时,底层的实现是TCP/UDP的协议,封装socket实现网络通信功能. 了解了网络通信的底层实现原理,在出现s ...

  5. sql server union与unionALL区别

    两种用法 一样, 查询字段类型需要一致 union 会自动去重 union all  不会去重 select name ,age from student union select name ,age ...

  6. 解决微信web页面键盘收起不回弹,导致按钮失效

    在文本框失去焦点时加入以下代码 $('input,textarea').blur(function () { setTimeout(function(){ window.scrollTo(,docum ...

  7. 象棋中“车”的攻击范围_Java

    代码如下: String[][] a = new String[8][8]; int h, l; Scanner scan = new Scanner(System.in); System.out.p ...

  8. wangeditor视频

    wangeditor网址http://www.wangeditor.com/ 目前使用的是3.11版本 使用步骤 1.引用wangEditor.min.js 2.代码 2.1 取得函数var E = ...

  9. Netty高性能原理和框架架构解析

    1.引言 Netty 是一个广受欢迎的异步事件驱动的Java开源网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端. 本文基于 Netty 4.1 展开介绍相关理论模型,使用场景,基本组件 ...

  10. 前端有用的CSS属性和JS方法

    1.CSS属性: 透明属性(值越大越不透明): IE:filter:alpha(opacity:30) Google:opacity:0.3 层次属性(值大的会在上面): z-index:100 2. ...