16. B
2026 旧版 · 非 2027 主源 · 原书检索 · 文字用于定位,公式与图表请回原页核验 · 本次导入快照
## 16. B
多个进程打开一个文件时,读/写指针的位置不同,它们保存在各自的用户打开文件表中,选项 I 错误。硬链接是基于索引节点的共享方式,指向同一个内存索引节点,选项 II 正确。不同进程获得的文件描述符是各自独立的,分别指向各自的用户打开文件表中的一项,选项 III 正确。
## 17. A
删除一个文件时,会根据文件控制块回收相应的磁盘空间,将文件控制块回收,并删除目录中对应的目录项。选项 B、C、D 正确。快捷方式属于文件共享中的软连接,本质上创建的是一个链接文件,其中存放的是访问该文件的路径,删除文件并不会导致文件的快捷方式被删除,正如在 Windows 中删除一个程序后,其快捷方式可能仍留在桌面上,但已无法打开。
## 二、综合应用题
### 01.【解答】
文件系统共有 $10 \times 10 = 100$ 个目录,若采用单级目录结构,目录表中有 100 个目录项,在检索一个文件时,平均检索的目录项数 = 目录项 / 2 = 50。采用两级目录结构时,主目录有 10 个目录项,每个子目录均有 10 个目录项,每级平均检索 5 个目录项,即检索一个文件时平均检索 10 个目录项,因此采用单级目录结构所需检索目录项数是采用两级目录结构的 $50 / 10 = 5$ 倍。
### 02.【解答】
1)可以建立链接。因为 F 是目录而 R 是文件,所以可以建立 R 到 F 的符号链接。除了符号链接,也可以通过硬链接的方式。
2)不一定能删除 R。由于 R 被多个目录共享,能否删除 R 取决于文件系统实现共享的方法。若采用基于索引节点的共享方法,则因删除后存在指针悬空问题而不能删除 R 节点。若采用基于符号共享的方法,则可以删除 R 节点。
3)不一定能删除 N。因为 N 的子目录中存在共享文件 R,而 R 节点本身不一定能被删除,所以 N 也不一定能被删除。
### 03.【解答】
1)① 因为目录 D 中没有已命名为 A 的文件,所以在目录 D 中,可以建立一个名为 A 的文件。② 因为在文件系统的根目录下已存在一个名为 A 的目录,所以根目录下的目录 C 不能改名为 A。
2)① 用户 G 需要通过依次访问目录 K 和目录 P,才能访问文件 S 和文件 T。为了提高文件访问速度,可在目录 G 下建立两个链接文件,分别链接到文件 S 和文件 T 上。这样用户 G 就可直接访问这两个文件。② 用户 E 可以修改文件 I 的存取控制表来对文件 I 加以保护,不让别的用户使用。具体实现方法是:在文件 I 的存取控制表中,只留下用户 E 的访问权限,其他用户对该文件无操作权限,从而达到不让其他用户访问的目的。
### 04.【解答】
1)因为磁盘块大小为 512B,所以索引块大小也为 512B,每个磁盘地址大小为 2B。因此,一个一级索引表可容纳 256 个磁盘地址。同样,一个二级索引表可容纳 256 个一级索引表地址,一个三级索引表可容纳 256 个二级索引表地址。这样,一个普通文件最多可有的文件页数为 $10 + 256 + 256 \times 256 + 256 \times 256 = 16843018$。
2)由图可知,目录文件 A 和 D 中的目录项都只有两个,因此这两个目录文件都只占用一个物理块。要读文件 J 中的某一页,先从内存的根目录中找到目录文件 A 的磁盘地址,将其读入内存(已访问磁盘 1 次)。然后从目录 A 中找出目录文件 D 的磁盘地址读入内存
<!-- page: 305 -->
(已访问磁盘2次)。再从目录D中找出文件J的FCB地址读入内存(已访问磁盘3次)。在最坏情况下,该访问页存放在三级索引下,这时候需要一级级地读三级索引块才能得到文件J的地址(已访问磁盘6次)。最后读入文件J中的相应页(共访问磁盘7次)。所以,若要读文件J中的某一页,最多启动磁盘7次。
3)由图可知,目录文件C和U的目录项较多,可能存放在多个链接在一起的磁盘块中。在最好情况下,所需的目录项都在目录文件的第一个磁盘块中。先从内存的根目录中找到目录文件C的磁盘地址并读入内存(已访问磁盘1次)。在C中找出目录文件I的磁盘地址并读入内存(已访问磁盘2次)。在I中找出目录文件P的磁盘地址并读入内存(已访问磁盘3次)。从P中找到目录文件U的磁盘地址并读入内存(已访问磁盘4次)。从U的第一个磁盘块中找出文件W的FCB地址并读入内存(已访问磁盘5次)。在最好情况下,要访问的页在FCB的前10个直接块中,按照直接块指示的地址读文件W的相应页(已访问磁盘6次)。所以,若要读文件W中的某页,最少启动磁盘6次。
4)为了减少启动磁盘的次数,可以将需要访问的W文件挂在根目录的最前面的目录项中。此时,只需读内存中的根目录就可找到W的FCB,将FCB读入内存(已访问磁盘1次),最差情况下,需要的W文件的那个页挂在FCB的三级索引下,因此读3个索引块需要访问磁盘3次(已访问磁盘4次)得到该页的物理地址,再去读这个页即可(已访问磁盘5次)。此时,磁盘最多启动5次。
05.【解答】
1)根目录的第一块常驻内存(root所指的/bin, /dev, /etc, /boot等可直接获得),根目录找到文件A需要5次读盘。由 $255 \times 2 + 2 = 512$ 可知,一个物理块在链式存储结构下可放2条记录及下一个物理块地址,而文件A共有598条记录,因此读取A的所有记录所需的读盘次数为 $598 / 2 = 299$ ,所以将文件A读到内存至少需读盘 $299 + 5 = 304$ 次。
2)当文件为连续文件时,找到文件A同样需要5次读盘,且知道文件A的地址后通过计算只需一次读盘即可读出第487条记录,所以至少需要 $5 + 1 = 6$ 次读盘。
4.3 文件系统
在学习本节时,请读者思考以下问题:
1)什么是文件系统?
2)文件系统要完成哪些功能?
本节除了“外存空闲空间管理”,其他都是2022年统考大纲的新增考点,这些内容都是比较抽象的、看不见也摸不着的原理,在常用的国内教材(如汤小丹的教材)中都鲜有涉及。若觉得不太好理解这些内容,则建议读者结合王道的最新课程进行学习。
4.3.1 文件系统结构
文件系统(File system)提供高效和便捷的磁盘访问,以便允许存储、定位、提取数据。文件系统有两个不同的设计问题:第一个问题是,定义文件系统的用户接口,它涉及定义文件及其属性、所允许的文件操作、如何组织文件的目录结构。第二个问题是,创建算法和数据结构,以便映射逻辑文件系统到物理外存设备。现代操作系统有多种文件系统类型,因此文件系统的层次结构也不尽相同。图4.19是一个合理的文件系统层次结构。
<!-- page: 306 -->
图4.19 一个合理的文件系统层次结构
(1)I/O 控制层
包括设备驱动程序和中断处理程序,在内存和磁盘系统之间传输信息。设备驱动程序将输入的命令翻译成底层硬件的特定指令,硬件控制器利用这些指令使 I/O 设备与系统交互。设备驱动程序告诉 I/O 控制器对设备的什么位置采取什么动作。
(2)基本文件系统
向对应的设备驱动程序发送通用命令,以读取和写入磁盘的物理块。每个物理块由磁盘地址标识。该层也管理内存缓冲区,并保存各种文件系统、目录和数据块的缓存。在进行磁盘块传输前,分配合适的缓冲区,并对缓冲区进行管理。管理它们对于系统性能的优化至关重要。
(3)文件组织模块
组织文件及其逻辑块和物理块。文件组织模块可以将文件的逻辑块地址转换为物理块地址,每个文件的逻辑块从 0 到 $N$ 编号,它与数据的物理块不匹配,因此需要通过转换来定位。文件组织模块还包括空闲空间管理器,以跟踪未分配的块,根据需求提供给文件组织模块。
(4)逻辑文件系统
用于管理文件系统中的元数据信息。元数据包括文件系统的所有结构,而不包括实际数据(或文件内容)。逻辑文件系统管理目录结构,以便根据给定文件名为文件组织模块提供所需要的信息。它通过文件控制块来维护文件结构。逻辑文件系统还负责文件保护。
4.3.2 文件系统布局
1. 文件系统在磁盘中的结构
文件系统存放在磁盘上,多数磁盘划分为一个或多个分区,每个分区中有一个独立的文件系统。文件系统可能包括如下信息:启动存储在那里的操作系统的方式、总的块数、空闲块的数量和位置、目录结构以及各个具体文件等。图4.20所示为一个可能的文件系统布局。
简单描述如下:
1) 主引导记录(Master Boot Record,MBR),位于磁盘的0号扇区,用来引导计算机,MBR的后面是分区表,该表给出每个分区的起始和结束地址。表中的一个分区被标记为活动分区。当计算机启动时,BIOS读入并执行MBR。MBR做的第一件事是确定活动分区,读入它的第一块,即引导块。
<!-- page: 307 -->
2)引导块(boot block),MBR执行引导块中的程序后,该程序负责启动该分区中的操作系统。每个分区都是统一从一个引导块开始,即使它不含有一个可启动的操作系统,也不排除以后会在该分区安装一个操作系统。Windows系统称之为分区引导扇区。
除了从引导块开始,磁盘分区的布局是随着文件系统的不同而变化的。文件系统经常包含有如图4.20所列的一些项目。
3)超级块(super block),包含文件系统的所有关键信息,在计算机启动时,或者在该文件系统首次使用时,超级块会被读入内存。超级块中的典型信息包括分区的块的数量、块的大小、空闲块的数量和指针、空闲的FCB数量和FCB指针等。
4)文件系统中空闲块的信息,可以用位示图或指针链接的形式给出。后面也许跟的是一组i节点,每个文件对应一个节点,i节点说明了文件的方方面面。接着可能是根目录,它存放文件系统目录树的根部。最后,磁盘的其他部分存放了其他所有的目录和文件。
图4.20 一个可能的文件系统布局
## 2. 文件系统在内存中的结构
内存中的信息用于管理文件系统并通过缓存来提高性能。这些数据在安装文件系统时被加载,在文件系统操作期间被更新,在卸载时被丢弃。这些结构的类型可能包括:
1)内存中的安装表(mount table),包含每个已安装文件系统分区的有关信息。
2)内存中的目录结构的缓存,包含最近访问目录的信息。
3)整个系统的打开文件表,包含每个打开文件的FCB副本、打开计数及其他信息。
4)每个进程的打开文件表,包含进程打开文件的文件描述符(Windows称之为文件匀称)和指向整个系统的打开文件表中对应表项的指针。
## 4.3.3 文件存储空间管理
一个存储设备可以按整体用于文件系统,也可以细分。例如,一个磁盘可以划分为2个分区,每个分区都可以有单独的文件系统。包含文件系统的分区通常称为卷(volume)。卷可以是磁盘的一部分,也可以是整个磁盘,还可以是多个磁盘组成RAID集,如图4.21所示。
在一个卷中,存放文件数据的空间(文件区)和FCB的空间(目录区)是分离的。因为存在很多种类的文件表示和存放格式,所以现代操作系统中一般都有很多不同的文件管理模块,通过它们可以访问不同格式的卷中的文件。卷在提供文件服务前,必须由对应的文件程序进行初始化,划分好目录区和文件区,建立空闲空间管理表格及存放卷信息的超级块。
文件存储设备分成许多大小相同的物理块,并以块为单位交换信息,因此,文件存储设备的管理实质上是对空闲块的组织和管理,它包括空闲块的组织、分配与回收等问题。
<!-- page: 308 -->
图4.21 逻辑卷与物理盘的关系
**数据概述** ➔ 磁盘空闲块管理的方法及特点(2019、2024)
1. 空闲表法
空闲表法属于连续分配方式,它与内存的动态分区分配类似,为每个文件分配一块连续的存储空间。系统为外存上的所有空闲区建立一张空闲表,每个空闲区对应一个空闲表项,其中包括表项序号、该空闲区的第一个空闲盘块号、该空闲区的空闲盘块数等信息。再将所有空闲区按其起始盘块号递增的次序排列,如表4.2所示。
表 4.2 空闲盘块表
[tbl-140.md](tbl-140.md)
盘块的分配:
空闲盘区的分配与内存的动态分配类似,也是采用首次适应算法、最佳适应算法等。例如,在系统为某新创建的文件分配空闲盘块时,先顺序地检索空闲盘块表的各表项,直至找到第一个其大小能满足要求的空闲区,再将该盘区分配给用户,同时修改空闲盘块表。
盘块的回收:
在对用户所释放的存储空间进行回收时,也采用类似于内存回收的方法,即要考虑回收区是否与空闲盘块表中插入点的前区和后区相邻接,对相邻接者应予以合并。
空闲表法的优点是具有较高的分配速度,可减少访问磁盘的I/O频率。对于较小的文件(1~5个盘块),可以采用连续分配方式为文件分配几个相邻的盘块。
2. 空闲链表法
空闲链表法是指将所有空闲盘区拉成一条空闲链,可分为以下两种。
(1)空闲盘块链
空闲盘块链是指将磁盘上的所有空闲空间以盘块为单位拉成一条链。每个盘块都有指向下一个空闲盘块的指针。当用户请求分配存储空间时,从链首开始,依次摘下适当数量的空闲盘块分配给用户。当用户释放存储空间时,将回收的盘块依次插入空闲盘块链的末尾。
空闲盘块链的优点是分配和回收一个盘块的过程非常简单。缺点是在为一个文件分配盘块时可能要重复操作多次,效率较低;又因它是以盘块为单位的,空闲盘块链会很长。
(2)空闲盘区链
空闲盘区链是指将磁盘上的所有空闲盘区拉成一条链,每个盘区包含若干相邻的盘块。每个
<!-- page: 309 -->
盘区含有指向下一个空闲盘区的指针和本盘区的盘块数。分配盘区的方法与内存的动态分区分配类似,通常采用首次适应算法。回收盘区时,同样也要将回收区与相邻接的空闲盘区合并。
空闲盘区链的优缺点正好与空闲盘块链的相反,优点是分配与回收的效率较高,且空闲盘区链较短。缺点是分配与回收的过程比较复杂。
## 3. 位示图法
**图解图表** 位示图的应用及相关计算(2010、2014、2015、2023)
位示图是利用二进制的一位来表示磁盘中一个盘块的使用情况,磁盘上的所有盘块都有一个二进制位与之对应。当其值为“0”时,表示对应的盘块空闲;为“1”时,表示已分配。这样,一个 $m \times n$ 位组成的位示图就可用来表示 $m \times n$ 个盘块的使用情况,如图4.22所示。
盘块的分配:
1)顺序扫描位示图,从中找出一个或一组其值为“0”的二进制位。
2)将找到的一个或一组二进制位转换成与之对应的盘块号。假设找到值为“0”的二进制位处在位示图的第 $i$ 行、第 $j$ 列,则其对应的盘块号 $b$ 应按下式计算($n$ 为每行位数):
$$
b = n (i - 1) + j
$$
3)修改位示图,令 $\mathrm{map}[i,j] = 1$ 。
图4.22 位示图法示意图
盘块的回收:
1)将回收盘块的盘块号转换成位示图中的行号和列号。转换公式为:
$$
\begin{array}{l}
i = (b - 1) \mathrm{DIV} n + 1 \\
j = (b - 1) \mathrm{MOD} n + 1 \\
\end{array}
$$
2)修改位示图,令 $\mathrm{map}[i,j] = 0$ 。
**注意**
如无特别提示,本书所用位示图的行和列都从1开始编号。特别注意,若题中指明从0开始编号,则上述计算方法要进行相应的调整。
位示图法的优点是很容易在位示图中找到一个或一组相邻接的空闲盘块。位示图很小,占用空间少,因此可将它保存在内存中,从而节省许多磁盘启动的开销。
位示图法的问题是位示图大小会随着磁盘容量的增加而增大,因此常用于小型计算机。
## 4. 成组链接法
空闲表法和空闲链表法都不适用于大型文件系统,因为这会使空闲表或空闲链表太大。UNIX系统中采用的是成组链接法,它结合了上述两种方法的思想而克服“表太长”的缺点。
成组链接法的思想:将空闲盘块分成若干组,如每100个盘块作为一组,每组的第一个盘块记录下一组的空闲盘块总数和空闲盘块号。这样,由各组的第一个盘块可以链接成一条链。第一
<!-- page: 310 -->
组的空闲盘块总数和空闲盘块号保存在内存的专用栈中,称为空闲盘块号栈。假设系统空闲区为第 201~7999 号盘块,则第一组的盘块号为 201~300……次末组的盘块号为 7801~7900,最末一组的盘块号为 7901~7999。最末一组只有 99 个盘块,它们的块号记录在前一组的 7900 号盘块中,该块中存放的第一个盘块号是 “0”,以作为空闲盘块链的结束标志,如图 4.23 所示。
简而言之,每组(除了最后一组)的第一块作为索引块,然后将这些索引块链接起来。
盘块的分配:
根据空闲盘块号栈的指针,将与之对应的盘块分配给用户,同时移动指针,并将栈中的空闲盘块数减 1。若该指针指向的是栈底的盘块号,则在该盘块号对应的盘块中保存的是下一组空闲盘块号,因此要将该盘块的内容读入栈,作为新的空闲盘块号栈的内容,并将原栈底盘块号对应的盘块分配出去(其中有用的数据已读入栈)。
例如,在图 4.23 中,分配盘块时,先依次分配 201~299 号盘块,当需要分配 300 号盘块时,首先将 300 号盘块的内容读入空闲盘块号栈,然后再分配 300 号盘块。
图 4.23 成组链接法示意图
盘块的回收:
将回收的盘块号存入空闲盘块号栈的顶部,同时移动指针,并将栈中的空闲盘块数加 1。当栈中的空闲盘块数已达 100 时,表示栈已满,将现有栈中的 100 个空闲盘块号存入新回收的盘块,并将该新回收的盘块号作为新栈底,再将栈中的空闲盘块数置为 1。
表示空闲空间的位向量表或空闲盘块号栈,以及卷中的目录区、文件区划分信息都要存放在磁盘中,一般放在卷头位置,在 UNIX 系统中称为超级块。在对卷中的文件进行操作前,超级块要预先读入内存,并且经常保持主存超级块与磁盘卷中超级块的一致性。
## 4.3.4 虚拟文件系统
虚拟文件系统(VFS)屏蔽了不同文件系统的差异和操作细节,向上为用户提供了文件操作的统一调用接口,如图 4.24 所示。当用户程序访问文件时,通过 VFS 提供的统一调用函数(如 open() 等)来操作不同文件系统的文件,而无须考虑具体的文件系统和实际的存储介质。
虚拟文件系统采用了面向对象的思想,它抽象出一个通用的文件系统模型,定义了通用文件系统都支持的接口。新的文件系统只要支持并实现这些接口,即可安装和使用。为了实现虚拟文件系统,系统抽象了四种对象类型。每个对象都包含数据和函数指针,这些函数指针指向操作这些数据的文件系统的实现函数。这四种对象类型如下。
### (1)超级块对象
表示一个已安装(或称挂载)的特定文件系统。超级块对象对应于磁盘上特定扇区的文件系统超级块,用于存储已安装文件系统的元信息。其操作方法包含一系列可在超级块对象上调用
<!-- page: 311 -->
的操作函数,主要有分配inode、销毁inode、读inode、写inode等。
图4.24 虚拟文件系统的示意图
## (2)索引节点对象
表示一个特定的文件。索引节点和文件是一对一的关系。只有当文件被访问时,才在内存中创建索引节点对象,每个索引节点对象都会复制磁盘索引节点包含的一些数据。索引节点对象还提供许多操作函数,如创建新索引节点、创建硬链接、创建新目录等。
## (3)目录项对象
表示一个特定的目录项。目录项对象是一个路径的组成部分,它包含指向关联索引节点的指针,还包含指向父目录和指向子目录的指针。不同于前面两个对象,目录项对象在磁盘上没有对应的数据结构,而是VFS在遍历路径的过程中,将它们逐个解析成目录项对象的。
## (4)文件对象
表示一个与进程相关的已打开文件。可以通过调用 open() 打开一个文件,通过调用 close() 关闭一个文件。文件对象和物理文件的关系类似于进程和程序的关系。文件对象仅是进程视角上代表已打开的文件,它反过来指向其索引节点。文件对象包含与该文件相关联的目录项对象,包含该文件的文件系统、文件指针等,还包含在该文件对象上的一系列操作函数。
当进程发起一个面向文件的系统调用时,内核调用 VFS 中的一个函数,该函数调用目标文件系统中的相应函数,将文件系统请求转换到面向设备的指令。以在用户空间调用 write() 为例,它在 VFS 中通过 sys_write() 函数处理,sys_write() 找到具体文件系统提供的写方法,将控制权交给该文件系统,最后由该文件系统与物理介质交互并写入数据,如图 4.25 所示。
图4.25 write()系统调用操作示意图
对用户来说,不需要关心不同文件系统的具体实现细节,只需要对一个虚拟的文件操作界面进行操作。VFS 对每个文件系统的所有细节进行抽象,使得不同的文件系统在系统中运行的进程看来都是相同的。严格来说,VFS 并不是一种实际的文件系统,它只存在于内存中,不存在于任何外存空间中。VFS 在系统启动时建立,在系统关闭时消亡。
## 4.3.5 文件系统挂载
如文件在使用前要打开那样,文件系统在进程使用之前必须先安装,也称挂载(Mounting)。
<!-- page: 312 -->
将设备中的文件系统挂载到某个目录后,就可通过这个目录来访问该设备上的文件。注意,这里的设备指的是逻辑上的设备,如一个磁盘上的不同分区都可视为不同的设备。
Windows 系统维护一个扩展的两级目录结构,用驱动器字母表示设备和卷。卷具有常规树结构的目录,与驱动器号相关联,还含有指向已安装文件系统的指针。特定文件的路径形式为 driver- letter:\path\to\file,访问时,操作系统找到相应文件系统的指针,并遍历该设备的目录结构,以查找指定的文件。新版的 Windows 允许文件系统安装在目录树下的任意位置,就像 UNIX 一样。在启动时,Windows 操作系统自动发现所有设备,并且安装所有找到的文件系统。
UNIX 使用系统的根文件系统,它是在系统启动时直接安装的,也是内核映像所在的文件系统。除了根文件系统,所有其他文件系统都要先挂载到根文件系统中的某个目录后才能访问。其他文件系统要么在系统初始化时自动安装,要么由用户挂载在已安装文件系统的目录下。安装文件系统的这个目录称为安装点,同一个设备可以有多个安装点,同一个安装点同时只能挂载一个设备。将设备挂载到安装点之后,通过该目录就可以读取该设备中的数据。
假定将存放在磁盘/dev/fd0上的 ext2 文件系统通过 mount 命令安装到/flp:
mount -t ext2 /dev/fd0 /flp
如需卸载该文件系统,可以使用 umount 命令。
贯穿本章内容有两条主线:第一条主线是介绍一种新的抽象数据类型——文件,从逻辑结构和物理结构两个方面进行;第二条主线是操作系统是如何管理“文件”的,介绍了多文件的逻辑结构的组织,即目录,还介绍了如何处理用户对文件的服务请求,即磁盘管理。只从宏观上认识是远不够的,从宏观上把握知识的目的是从微观上更加准确地掌控细微知识点,在考试中取得好成绩。读者要通过反复做题和思考,不断加深自己对知识点的掌握程度。