文件的基本概念

第 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)、可执行文件
按存取控制属性可执行文件、只读文件、读/写文件
按组织形式和处理方式普通文件、目录文件、特殊文件
文件类型读写最终落到哪里
普通文件磁盘数据块,系统不解释内容
目录文件磁盘数据块,系统按目录项格式解释,禁止用户直接写
特殊文件设备驱动程序,根本不落到磁盘

考点

  • 自底向上三层:数据项 → 记录 → 文件,基本数据项是不可再分的最小单位
  • 关键字必须唯一标识一条记录
  • 文件属性中,名称是唯一人类可读的,标识符是内部数字
  • 最小操作集合是创建、写、读、重定位、删除、截断六个,打开与关闭不在其中
  • 特殊文件的读写转交设备驱动,不访问磁盘数据块
  • 文件名存在目录项里,不在文件里

链接