文件的基本概念
第 3 章解决的是内存里的数据怎么放,但内存断电即失,容量也有限。要长期保存信息,必须放到外存上。
于是产生一个新问题:外存是一片按物理块编号的连续空间,用户不可能记住”我的论文在第 38912 号盘块”。用户需要的是”按名字取东西”,而磁盘只提供”按编号取块”。 文件系统存在的全部意义,就是把后者包装成前者。
这一节先把”文件”这个抽象本身讲清楚:它由什么构成、有哪些属性、分成哪些类。
机制
自底向上地定义文件
王道用三层结构自底向上地给出文件的定义,这个顺序不是随意的——每一层都是对下一层的成组封装。
数据项是文件系统中最低级的数据组织形式,分两类。基本数据项是用于描述一个对象某种属性的字符集,是数据中不可分割的最小单位,例如一个人的姓名、年龄、出生日期。组合数据项则由若干基本数据项构成,例如”工资”这一项可以由基本工资、绩效、扣款等基本数据项组合而成。
记录是一组相关数据项的集合,用于描述一个对象在某方面的属性。例如一名学生的学号、姓名、年龄、所在院系合起来构成一条学生记录。为了在一堆记录里区分出某一条,需要指定一个或几个数据项作为关键字——关键字必须能唯一标识一条记录,学号可以,姓名通常不行。
文件是创建者定义的一组相关信息的集合。逻辑上,文件可以分为有结构文件和无结构文件两种:有结构文件由若干相似的记录组成(又称记录式文件),无结构文件则被看成一个连续的字符流(又称流式文件)。
graph LR A["基本数据项<br/>姓名 / 学号 / 年龄<br/><i>不可再分</i>"] --> B["记录<br/>一名学生的全部属性<br/><i>由关键字唯一标识</i>"] B --> C["文件<br/>全班学生记录的集合"] A2["组合数据项<br/>工资 = 基本+绩效+扣款"] --> B classDef base fill:#dbeafe,stroke:#2563eb,color:#1e3a8a classDef mid fill:#fef3c7,stroke:#d97706,color:#78350f classDef top fill:#dcfce7,stroke:#16a34a,color:#14532d class A,A2 base class B mid class C top
关联对照:这套结构与关系数据库的对应关系
三层结构与关系数据库的模型高度同构:数据项对应字段(列)、记录对应元组(行)、文件对应表,“关键字”对应的正是主键,且两者对”唯一标识”的要求完全一致。
边界在于谁来解释这些结构。数据库自己保存模式(schema),知道每个字段的类型与约束,因此能提供索引、事务、查询语言。文件系统不保存任何模式——它只负责把字节按顺序存下来并原样取出,至于第 3 到第 10 个字节是不是”年龄”,只有应用程序自己知道。
所以现代操作系统里绝大多数文件是无结构的字节流,“记录式文件”主要是早期以磁带、批处理为背景的产物,在 408 中作为概念考查。
文件的属性
一个文件除了自身的数据,还附带一组属性,这些属性并不存放在文件内容里,而是由文件系统单独管理(存放位置见 4.1.2):
名称是唯一以人类可读形式保存的信息。标识符是文件系统内部使用的一个数字,用户不可读——这两者的区分很关键:人用名字,系统用编号。类型用于支持不同格式的文件。位置指向文件在设备上的存放地址。大小记录当前文件大小。保护记录访问控制信息。此外还有创建时间、最后修改时间和文件所有者信息。
文件的基本操作
操作系统向用户提供的最小操作集合是六个:创建、写、读、重定位(文件寻址)、删除、截断。这六个之所以是”最小集合”,是因为其余复杂操作(如复制)都可以由它们组合完成——复制就是”创建一个新文件 + 从旧文件读 + 向新文件写”。
打开与关闭这两个操作在这个最小集合之外,因为它们并不改变文件本身,只改变进程与文件之间的连接状态。详见 4.1.3。
文件的分类
王道给出四种分类口径,考试中主要考查辨析而非记忆:
按用途分为系统文件、用户文件、库文件。按数据形式分为源文件、目标文件、可执行文件。按存取控制属性分为可执行文件、只读文件、读/写文件。按组织形式和处理方式分为普通文件、目录文件、特殊文件。
边界
普通文件、目录文件与特殊文件的界限
疑问点:普通文件与特殊文件的划分依据
教材原文:“按组织形式和处理方式分类,分为普通文件、目录文件、特殊文件。” 此处”普通”与”特殊”的界限是什么。
划分依据不是文件的内容,而是”读写这个文件时,操作系统把它的内容当作什么来解释”。
普通文件的内容就是数据本身。操作系统不解释其中任何一个字节,只负责原样存取——一个源程序、一张图片、一段视频对文件系统而言毫无区别。
目录文件的内容是由文件目录项组成的表。它在磁盘上同样占用数据块,形式上与普通文件一样,但操作系统会按目录项的格式去解析它,并且不允许用户程序直接用普通的写操作去改它——必须通过创建、删除文件等系统调用间接修改。原因很直接:目录一旦被写坏,整棵目录树就找不到文件了。
特殊文件指各种 I/O 设备在文件系统中的映射(UNIX 与 Linux 中位于 /dev)。它的”内容”根本不在磁盘上——对它的读写会被转交给设备驱动程序,最终变成对物理设备的操作。向 /dev/lp0 写入就是打印,从 /dev/tty 读取就是读键盘。广义:FIFO(管道)、socket 等非普通文件有时也会被归入特殊文件。
所以三者的真正分界是:
普通文件的读写落到磁盘数据块;目录文件的读写落到磁盘数据块但由系统解释格式;特殊文件的读写根本不落到磁盘,而是落到设备驱动。
这也解释了 UNIX 那句著名的设计原则”一切皆文件”的实际含义:统一的不是存储介质,而是访问接口——都用 open/read/write/close,至于底下是磁盘还是打印机,由文件类型决定分派到哪套处理程序。这套分派机制在 4.3.4 虚拟文件系统中会具体展开。
文件名不是文件的一部分
初学时容易默认”文件名存在文件里”。实际上文件名保存在目录项中,而不是文件自身的数据里。
这一点的后果在文件共享时才会显现:同一个文件可以在不同目录下以不同的名字被访问(硬链接),因为名字属于”通往文件的那条路”,不属于文件。
逻辑上的”记录”与物理上的”块”
记录是用户视角的划分单位,盘块是磁盘视角的划分单位,两者互不相干。 一条记录可能跨越两个盘块,一个盘块也可能装下多条记录。
把用户的记录序列映射到磁盘的盘块序列,正是文件系统要做的事,具体在 4.1.4 与 4.1.5 两节展开。
对照速查
| 层次 | 定义 | 关键点 |
|---|---|---|
| 数据项 | 最低级的数据组织形式 | 基本数据项不可再分;组合数据项由基本数据项构成 |
| 记录 | 一组相关数据项的集合 | 靠关键字唯一标识 |
| 文件 | 创建者定义的一组相关信息的集合 | 分有结构(记录式)/ 无结构(流式) |
| 分类口径 | 类别 |
|---|---|
| 按用途 | 系统文件、用户文件、库文件 |
| 按数据形式 | 源文件、目标文件(中间文件,更细的是编译/汇编之后、链接之前生成的文件如.o、.obj)、可执行文件 |
| 按存取控制属性 | 可执行文件、只读文件、读/写文件 |
| 按组织形式和处理方式 | 普通文件、目录文件、特殊文件 |
| 文件类型 | 读写最终落到哪里 |
|---|---|
| 普通文件 | 磁盘数据块,系统不解释内容 |
| 目录文件 | 磁盘数据块,系统按目录项格式解释,禁止用户直接写 |
| 特殊文件 | 设备驱动程序,根本不落到磁盘 |
考点
- 自底向上三层:数据项 → 记录 → 文件,基本数据项是不可再分的最小单位
- 关键字必须唯一标识一条记录
- 文件属性中,名称是唯一人类可读的,标识符是内部数字
- 最小操作集合是创建、写、读、重定位、删除、截断六个,打开与关闭不在其中
- 特殊文件的读写转交设备驱动,不访问磁盘数据块
- 文件名存在目录项里,不在文件里
链接
- 🏠 返回总览:操作系统第 4 章:文件管理总览
- ➡️ 下一节:4.1.2 文件控制块和索引节点
- 🔗 属性存放在哪里,见 4.1.2 文件控制块和索引节点
- 📖 名词库:第 4 章名词库