1. 先搞清楚文件管理这一章到底在考什么
1.1 从用户视角到系统视角的两次跳转
操作系统里的文件管理,是整本书里少有的那种"上手觉得特别亲切、深入之后到处是坑"的章节。为什么亲切?因为文件、目录、路径、复制粘贴这些词,我们每天都在用。打开电脑找一份文档,拖进文件夹,改个名字,这些都是文件管理。但考研考的不是你会不会用资源管理器,它要的是你在两个层面上来回切换:一个是用户眼里"按名字找文件"的逻辑视图,一个是系统眼里"块号、索引、指针"的物理视图。这两个视图之间的映射关系,才是这一章的命门。
我第一遍学的时候,最大的误区就是把文件管理当成"背概念"的章节,目录结构背一背、分配方式背一背,题也做得差不多。结果一刷真题发现,概念题的正确率还行,但凡是带计算的题,比如索引块能放多少地址项、位示图第几个字第几位对应哪个盘块、磁盘调度移动了多少个磁道,就全线崩溃。后来才明白,这一章的真正难点不在"记住有哪几种方法",而在于"给定具体参数,你能不能把链条推完"。
这一章的内容主干其实可以浓缩成四块:文件与目录的基本概念、文件的逻辑结构与物理结构、目录与文件共享保护、磁盘组织与调度。听起来不多,但每一块往下挖都能挖出大量细节。比如逻辑结构里顺序文件、索引文件、索引顺序文件各有什么优缺点;物理结构里连续分配、链接分配、索引分配各自适合什么场景;空闲空间管理里位示图、成组链接法怎么算;磁盘调度里五种算法的手算流程。这些东西单独拿出来都不难,但组合成一道大题,就容易漏条件、算错方向。
1.2 考纲分布与题型规律
从历年真题来看,文件管理的分值占比通常稳定在 15% 到 25% 之间,属于中等偏上的章节。选择题里高频出现的是:文件的逻辑结构对比、目录结构特点、硬链接与软链接的区别、文件分配方式的优缺点、空闲空间管理方法的适用场景、磁盘调度算法的特性。大题则集中在这几个方向:给参数算最大文件长度、给请求序列算磁盘调度总寻道距离、给位示图算盘块号、给成组链接法算分配回收过程。
我的经验是,这一章的选择题喜欢考"边界情况"。比如问"哪种分配方式不支持随机访问",答案是隐式链接分配;问"哪种目录结构适合文件共享",答案是无环图目录;问"FAT 表的作用",答案是实现显式链接并支持随机访问。这些点如果只记结论,很容易在四个选项里被绕晕,因为选项往往是把两三个相近概念的属性拼在一起。真正稳的做法是,每记住一个方法,就顺手记住它的三个属性:能不能随机访问、有没有外部碎片、扩不扩容方便。
大题则更考验流程完整性。比如一道磁盘调度的大题,往往会同时问三种算法的移动距离,还可能追问"哪种算法对两端磁道更公平"。如果你只是背了算法名字,到了计算环节漏掉折返距离、忘了加上回到最小请求的移动量,分数就没了。所以这一章的正确打开方式是:概念用来定方向,计算用来拉分,两者缺一不可。
2. 文件与目录:概念题最容易翻车的地方
2.1 文件的逻辑结构怎么选
文件的逻辑结构,指的是从用户角度看到的文件内部记录是怎么组织的。这里最常见的四种是:顺序文件、索引文件、索引顺序文件、直接文件(散列文件)。很多人学完就记得一句"顺序文件只能顺序找,索引文件能随机找",这个理解不能说错,但太粗了,考试一变形就容易错。
顺序文件里的记录是挨着放的,分定长和变长两种。定长记录的顺序文件,因为每条记录长度一样,所以其实也能算出第 n 条记录的起始位置,随机访问是可行的;变长记录就不行了,因为前一条的长度不知道,只能从头往下捋。所以"顺序文件只支持顺序访问"这句话,严格来说是针对变长记录的。这个细节点,我是在一道选择题里被打脸之后才记住的。
索引文件是给文件建一张索引表,每条记录对应索引表里的一项,记录本身的物理位置可以乱放。它的好处是随机访问非常快,找第 n 条记录直接查索引表就行。代价是索引表本身要占存储空间,记录一多,索引表也大。索引顺序文件是对索引文件的改良,它不记录每条记录的位置,而是分组。组内用顺序排列,组间建一张索引。检索的时候先查索引定位到组,再在组内顺序找。这样一来,索引表的规模小了很多,检索效率介于顺序文件和索引文件之间。教材里给过一个估算,顺序文件平均查找次数约是记录数的一半,而索引顺序文件大概能做到记录数的平方根量级,这个量级差异在数据量大的时候非常可观。
直接文件又叫散列文件,用哈希函数把关键字映射到物理地址,理想情况下一次就能命中。问题还是老问题:哈希冲突。冲突处理不好,性能会掉得很快。
我在整理这部分的时候,自己画过一张对照表,把每种结构的"组织方式、检索方式、是否支持随机、主要代价"四列列清楚。这个动作看着笨,但比反复读教材管用得多。因为考试考的就是这些属性的排列组合。
2.2 目录结构的三代演进
目录结构一般讲四种:单级目录、两级目录、树形目录、无环图目录。这四种不是随便并列的,它们其实是一条演进路线,每一代都在解决上一代的问题。
单级目录最简单,整个文件系统就一张表,所有文件全在一起。它解决了"文件怎么被命名和查找"的最基本问题,但立刻带来两个麻烦:第一,不能重名,两个用户各自想建一个叫report的文件就冲突了;第二,文件一多,检索效率直线下降。
两级目录把目录分成主目录和用户目录,主目录下每个用户有自己的目录。这样不同用户之间可以随便重名,因为系统会先定位到用户目录再找文件。但两级目录的粒度还是太粗,用户在自己目录里没法再分类,所有文件还是堆在一层。
树形目录是现在最常见的形态,目录可以嵌套,形成树。它支持绝对路径和相对路径,也引入了"当前目录"的概念,这样用户在某一层目录里可以直接用文件名访问同级文件,不用每次都写全路径。树形目录的问题是文件共享不方便,因为一个文件在树里只能有一个位置,想让两个目录都能访问同一个文件,就做不到。
无环图目录就是来补这个短板的。它允许一个目录或文件被多个父目录指向,形成一个有向无环图。这样就能实现真正的共享。但它带来一个新问题:删除。如果多个父目录指向同一个文件,你从一个目录里删掉它,文件到底该不该真删?标准解法是引入引用计数,每多一个链接就加一,删除时减一,减到零才真正回收。这个引用计数的思路,和后面硬链接的机制是一套逻辑,理解了一个另一个就通了。
我踩过的一个坑是,一直以为"目录也是文件"。严格来说,目录在实现上确实占用磁盘块、也有一张表,但它的记录内容是文件名到文件位置的映射,和我们平时说的普通文件在内容语义上不一样。考试如果问"目录项里存放的是什么",答案通常是文件名和指向文件控制块的指针(或索引节点号),不是文件内容本身。
2.3 硬链接与软链接,本质区别到底是什么
硬链接和软链接是这一章反复考的点,而且特别容易记混。我用一个尽量直白的说法来区分它们。
硬链接的本质是:多个目录项指向同一个索引节点。也就是说,文件实体只有一份,索引节点只有一个,只是有多个名字指向它。因为用的是同一个索引节点,所以索引节点里有个引用计数,每加一个硬链接就加一,删一个就减一,减到零文件才真正消失。硬链接的特点是不能跨文件系统,因为不同文件系统的索引节点编号体系是独立的;一般来说也不允许对目录创建硬链接,否则目录树就可能出现环,遍历会出问题。
软链接的本质是:创建一个新的文件,这个文件的内容就是一条路径字符串。它有自己的索引节点,是独立的一份文件,只不过内容指向别处。访问软链接的时候,系统会读取它保存的路径,然后重新走一遍路径解析,找到目标文件。所以目标文件被删了,软链接依然存在,只是变成了悬空链接,访问会报错。软链接可以跨文件系统,也可以指向目录。
有一道很经典的考法:问"删除原文件后,硬链接和软链接分别会怎样"。硬链接不受影响,因为它本来就是文件的另一个名字,文件本身还在(引用计数没到零);软链接会失效,因为它只是个记录路径的影子。反过来,如果问"软链接的创建是否增加原文件的引用计数",答案是不增加,因为它不指向索引节点,只指向路径。
还有一个更细节的点:硬链接的ls -l里显示的是链接数,软链接显示的是箭头指向。这个区分在实际操作中一眼就能看出来,但考试里给的是文字描述,所以必须从"指向索引节点还是指向路径"这个根本差异去判断。我个人建议把这两个的定义写成一句话背下来:硬链接是同一索引节点的多个名字,软链接是一个存路径的独立文件。把这句话记牢,绝大部分变形题都能拆开。
3. 文件系统实现:分配方式和空闲空间管理
3.1 三种物理结构分配的取舍逻辑
文件的物理结构,也就是文件在磁盘上到底怎么放。这里三种主流方式是连续分配、链接分配、索引分配,每种都有自己的死穴。
连续分配要求文件占用的磁盘块在物理上是连续的。它的优点是顺序访问和随机访问都快,因为只要知道起始块号和长度,就能直接算出任意位置。但它有两个硬伤:一是必须提前知道文件大小,不好动态增长;二是频繁创建删除会产生外部碎片,时间长了磁盘上到处是零散的小空档,用不上。
链接分配是把文件分成若干块,每块里存一个指针指向下一块。隐式链接就是指针存在数据块里,这样做的后果是只能从第一块开始顺藤摸瓜,想读最后一块必须把前面全走一遍,随机访问基本废了。显式链接是把所有指针抽出来,单独放在一张文件分配表里,也就是 FAT。FAT 常驻内存,查表就是内存操作,所以显式链接支持随机访问。代价是 FAT 表本身占内存,磁盘越大这张表越大。
索引分配是给每个文件建一张索引块,索引块里按顺序存文件所有数据块的块号。要找第 n 块,直接查索引块第 n 项就行,随机访问很自然。小文件的问题是一个索引块可能只用了一两项却占了一整块;大文件的问题是一个索引块装不下,于是要引入多级索引或者混合索引。
混合索引是考研特别喜欢的形式,典型结构是:若干直接地址项,加一级间接、二级间接、三级间接各一个。直接项直接指向数据块;一级间接项指向一个索引块,索引块里全是数据块地址;二级间接项指向一个索引块,里面的每一项再指向一个索引块,再下一层才是数据块;三级依次类推。
举个具体的算法。假设磁盘块大小是 4KB,每个地址项占 4 字节,那么一个索引块能放 4096 / 4 = 1024 个地址。如果结构是 10 个直接项 + 1 个一级间接 + 1 个二级间接 + 1 个三级间接,那么:
| 层级 | 地址项数量 | 可寻址数据量 |
|---|---|---|
| 10 个直接项 | 10 | 10 × 4KB = 40KB |
| 一级间接 | 1024 | 1024 × 4KB = 4MB |
| 二级间接 | 1024² | 1024² × 4KB = 4GB |
| 三级间接 | 1024³ | 1024³ × 4KB = 4TB |
所以这个文件系统单个文件的最大长度大约是 4TB 加上前面那点零头。注意这里算的是"能寻址的数据量",一级间接算的是索引块里 1024 个地址各自指向一个数据块,而不是索引块本身的大小。这个理解如果错了,整个算式就全错。我在早期做这类题时,总想把索引块本身也算进文件大小,其实就是错的,索引块是元数据,不占文件内容。
3.2 空闲空间管理四种方法对照
磁盘上哪些块是空的、哪些被占了,系统得有一本账。这本账有四种常见记法:空闲表法、空闲链表法、位示图法、成组链接法。
空闲表法就是维护一张表,每一行记录一段连续空闲区的起始块号和长度。它天然适合连续分配,因为找连续空间很方便。但如果空闲区很零散,表就会很长。
空闲链表法分两种。空闲盘块链是把每个空闲块串起来,分配的时候从链头摘一块,回收的时候挂回去。实现简单,但一次要分配多块就得反复摘链。空闲盘区链是把连续的一段空闲区当作一个结点串起来,这样一次能分配一大段,但回收和合并逻辑会更复杂。
位示图法是最常见的考法。它用一个二进制位对应一个磁盘块,0 表示空闲,1 表示占用(具体约定看题目),很多个位组成一个字。位示图通常放在内存里,检索起来方便,尤其是找连续空闲块时可以按字快速扫描。位示图的缺点是,磁盘块数越多,需要的位数越多,位示图本身占的内存也就越大。
成组链接法是 UNIX 系统里用的方案,专门为大型文件系统设计。它的核心思路是不把空闲块一个一个串起来,而是分组。每组的第一块记录下一组的信息。系统在内存里维护一个栈结构,栈里存的是当前这一组空闲块的块号,还有一个计数。分配时从栈顶取,取到这个组只剩最后一项时,那个最后一项其实指向的是下一组的入口,读进来之后栈就切换到了下一组。回收时反过来,往栈里压,如果栈满了就把栈里所有块号写到新回收的那块上,让它成为新的组首。
这个机制的理解难点在于"栈里最后一项兼作下一组的指针"这个设计。它巧妙就巧妙在省了额外的存储,但初次看的时候很容易晕。我当时的办法是拿一张纸,画三层盒子,模拟分配五块、回收三块,走两遍流程,之后就再也没忘过。
3.3 位示图和成组链接法的计算模板
位示图的计算题很有套路,但起点一定要看清楚:块号是从 0 开始还是从 1 开始,字和位是从 0 还是从 1 开始编号。这几个假设不同,公式就不一样。
以最常见的约定为例:字长为 32 位,位示图的字和位都从 0 开始编号,磁盘块号也从 0 开始。那么第 i 个字、第 j 位对应的块号就是i × 32 + j。反过来,已知块号 b,它所在的是第b / 32个字,第b % 32位。
如果题目改成从 1 开始编号,那么第 i 个字、第 j 位对应的块号就是(i - 1) × 32 + j。这个变形我在真题里见过,一开始总觉得是题目出错,后来发现是自己没看清约定。所以做这类题,第一步永远是找题目的编号起点。
成组链接法的计算题一般是给一个初始状态,让你算分配某个数量的块之后,栈里的内容变成什么样,或者让你算回收之后怎么变。我的解法是把它当成一个栈加一个链表:栈是当前能直接分配的一组,栈底最后一项存的是下一组的地址。分配就是弹出栈顶,回收就是压入栈顶,栈满时把整栈写到新释放的块里,那块就成为新的组首。只要按这个规则一步步走,通常不会错。需要注意的一个坑是,栈满的判断精确到"栈里还剩一个位置"还是"完全满",不同教材的写法有差异,考试时以题目给出的容量为准。
4. 磁盘组织与管理:手算题的主战场
4.1 磁盘访问时间的三段拆解
磁盘读写一次的时间,由三部分构成:寻道时间、旋转延迟、传输时间。
寻道时间是磁头从当前位置移动到目标磁道所花的时间。教材里的模型通常是Ts = m × n + s,其中 n 是跨越的磁道数,m 是每移动一个磁道的耗时,s 是启动时间。做计算题的时候,如果题目没给 m 和 s,一般就不用套这个公式,直接用"磁道数 × 单位时间"或者干脆只比较磁道移动数。
旋转延迟是等待目标扇区转到磁头下方的时间。如果磁盘转速是 r 转每秒,那么平均旋转延迟就是转半圈的时间,也就是1 / (2r)。这个"平均取半圈"的假设要记住,因为题目经常给转速不给延迟,就等你换算。比如转速是 7200 转每分钟,换算成每秒就是 120 转,平均旋转延迟就是 1/240 秒,大约是 4.17 毫秒。
传输时间是把数据真正读出来或写进去的时间,公式是Tt = b / (r × N),b 是要读写的字节数,N 是每条磁道上的字节数,r 还是转速。这个量级通常比前两者小,所以优化磁盘性能主要是在减少寻道和旋转延迟上做文章。
减少延迟还有两个经典手段:交替编号和错位命名。交替编号是指把逻辑上相邻的扇区在物理上隔开编号,比如逻辑扇区 1、2、3、4 在物理上排成 1、3、2、4 这种交错形式。这样做是为了给磁盘控制器留出处理时间,避免读完一个扇区后,下一个还没处理完就已经转过去了。错位命名则是把相邻磁道的起始扇区错开,让磁头换道之后不用等太久就能读到下一段数据。这两个概念考选择题比较多,理解成"为了配合硬件处理速度做的物理排布优化"就够用了。
4.2 五种调度算法的手算流程
磁盘调度的目标很朴素:让磁头移动的总距离尽量小。五种算法分别是先来先服务 FCFS、最短寻道时间优先 SSTF、扫描算法 SCAN、循环扫描 C-SCAN,还有它们的改进版 LOOK 和 C-LOOK。
FCFS 就是按请求到达顺序服务,公平但效率低,磁头可能来回横跳。SSTF 每次挑离当前磁头最近的请求,效率明显提升,但有个著名问题:如果一直有靠近中间磁道的请求进来,两端磁道的请求可能永远等不到,也就是饥饿。SCAN 又叫电梯算法,磁头朝一个方向一路扫过去,扫到头再反向,这样两端都能被照顾到,但中间磁道会被更频繁地访问,两端的等待时间其实比中间长。C-SCAN 是为了解决这个不公平:磁头只朝一个方向服务,扫到端点后快速返回另一端重新开始,返回途中不服务请求,这样各个磁道的等待时间就均匀了。LOOK 和 C-LOOK 是它们的实用版本,区别在于磁头不是扫到磁盘端点才折返,而是扫到最远的那个请求就折返,不浪费空跑的距离。
手算的时候,我习惯画一条数轴,把请求点和初始位置标上去,然后按算法规则连线,最后把每一段的距离加起来。这个方法笨,但非常稳,尤其是 C-SCAN 那种要折返的情况,画出来一眼就能看清哪段要算、哪段不算。
4.3 一道综合计算题的完整推演
光讲规则没用,我们直接上手算一遍。假设磁头初始在 100 号磁道,正在向磁道号增大的方向移动,请求序列是:55、58、39、18、90、160、150、38、184。
先算 FCFS,按顺序服务:
100 到 55 是 45,55 到 58 是 3,58 到 39 是 19,39 到 18 是 21,18 到 90 是 72,90 到 160 是 70,160 到 150 是 10,150 到 38 是 112,38 到 184 是 146。加起来是 45+3+19+21+72+70+10+112+146 = 498。
再算 SSTF。当前在 100,最近的请求是 90,距离 10。到 90 之后,最近的变成 58,距离 32。接着是 55,距离 3。然后 39,距离 16。然后 38,距离 1。然后 18,距离 20。这时候只剩下 150、160、184 三个,最近的 150 距离 132。接着 160,距离 10。最后 184,距离 24。总和是 10+32+3+16+1+20+132+10+24 = 248。可以看到,SSTF 比 FCFS 少走了大半。
接着算 SCAN。磁头当前向大方向移动,一路扫过去服务 150、160、184,然后折返,再服务 90、58、55、39、38、18。如果按 LOOK 式处理,也就是扫到最远的请求 184 就折返:
100 到 150 是 50,150 到 160 是 10,160 到 184 是 24,这段共 84。折返后,184 到 90 是 94,90 到 58 是 32,58 到 55 是 3,55 到 39 是 16,39 到 38 是 1,38 到 18 是 20,这段共 166。总计 84 + 166 = 250。
如果严格按"扫到磁盘端点"来算,假设端点磁道号是 199,那么去程要走到 199(100 到 199 是 99),回程 199 到 18 是 181,总计 280。考试的时候要看题目怎么描述,如果题目给了最大磁道号,那多半是要你按端点算,如果只说"扫到最远请求",就按 250 算。这是这类题最容易被扣分的地方。
最后算 C-SCAN。它只朝一个方向服务,扫到最远请求后,直接返回最小的请求端重新开始,返回途中不服务。按这个规则:去程 100 到 184 共 84,返回 184 到 18 是 166,然后从 18 开始向大方向服务剩下的 38、39、55、58、90,这段距离是 90 - 18 = 72。总计 84 + 166 + 72 = 322。
把这几个结果整理成一张表:
| 算法 | 磁头移动总距离 | 主要特点 |
|---|---|---|
| FCFS | 498 | 公平,效率低 |
| SSTF | 248 | 效率高,可能饥饿 |
| SCAN(LOOK 式) | 250 | 兼顾两端,中间优先 |
| SCAN(扫到端点) | 280 | 严格按端点折返 |
| C-SCAN | 322 | 等待时间均匀,移动距离偏大 |
这张表里有几个信号值得注意。SSTF 的距离最短,但它有饥饿风险;C-SCAN 距离最大,但它的价值在公平性而不是总距离。题目如果问"哪种总移动距离最小",答案往往是 SSTF;如果问"哪种对各个磁道的响应最公平",答案就是 C-SCAN。这两个问题问的不是一回事,千万不要看到距离小就无脑选。
5. 复习过程中踩过的坑和常见问题速查
5.1 概念类易错点清单
这一章的概念题,错法就那么几种,我把自己踩过的和见过的整理一下。
第一个坑是把"文件的逻辑结构"和"文件的物理结构"搞混。逻辑结构是从用户角度看记录怎么排,物理结构是文件在磁盘上怎么放。顺序文件是逻辑结构,连续分配是物理结构,两者名字里都有"顺序"或"连续",特别容易串。我的记忆方法是:逻辑结构管记录,物理结构管磁盘块。
第二个坑是搞不清哪些分配方式支持随机访问。准确的说法是:连续分配支持随机访问,隐式链接分配不支持,显式链接分配(FAT)支持,索引分配支持。这个判断题几乎每年都会变个形出现。
第三个坑是目录结构和文件共享的关系。树形目录不支持文件共享,无环图目录支持。这个结论要和对引用计数的理解绑在一起记,不然容易记反。
第四个坑是硬链接能不能跨文件系统。答案是通常不能。软链接可以。这个点经常和"硬链接是否增加引用计数"一起考,前者考的是索引节点编号的独立性,后者考的是共享同一索引节点的机制。
第五个坑是固态硬盘的特性。SSD 没有机械部件,所以没有寻道时间和旋转延迟,随机访问很快。它的读写单位是页,擦除单位是块,擦除次数有限,所以需要闪存翻译层做逻辑地址到物理地址的映射,还需要磨损均衡来延长寿命。这些点如果只看结论,很容易和机械硬盘的特性混在一起。
5.2 计算类易错点清单
计算类的错误更隐蔽,因为步骤对但参数算错,结果就全错。
索引块地址项数量算错是最常见的一种。记住这个换算链:索引块容量除以地址项大小,就是地址项个数。4KB 的块放 4 字节的地址,就是 1024 项;放 8 字节的地址,就是 512 项。一旦这个基数错了,后面几级间接全部跟着错。
多级索引的层数理解错也很常见。一级间接意味着要多读一个索引块才能拿到数据块地址;二级间接要读两个索引块;三级要读三个。做题的时候如果题目问"访问某个位置需要读几次磁盘",就要把这个层数算进去,不能只数数据块。
位示图的编号起点看错,是另一个高发错误。字从 0 开始还是从 1 开始,位从 0 开始还是从 1 开始,块号从 0 开始还是从 1 开始,这三个假设任意一个不同,公式就不同。我的做法是每次做题先把这三个假设写在草稿纸最上面,再动笔。
磁盘调度漏算折返距离,是最冤的一种错。C-SCAN 的返回段到底算不算、SCAN 是扫到端点还是扫到最远请求,这些都要看题目的措辞。我现在的习惯是,凡是遇到"循环""扫描"这类字眼,先在草稿上画数轴,把去程和返程分开标,最后再分别求和。
转速和时间的换算也容易出错。7200 转每分钟和 120 转每秒是同一个东西,但很多人一急就把分钟当秒用。平均旋转延迟永远是转半圈的时间,这个定式要背牢。
5.3 我的刷题顺序和时间分配
最后说说我自己的复习节奏,不一定适合所有人,但可以参考。第一遍我把这一章的教材过了一遍,重点是把每个概念的定义和适用场景弄清楚,做题只做选择题,大题先跳过。第二遍开始整理对比表格,把逻辑结构的四种、目录结构的四种、分配方式的三种、空闲管理的四种、调度算法的五种,全部横向列出来对比。这个动作大概花了两三天,但后面查漏补缺的时候特别省事。
第三遍才是集中攻计算题。我按题型分类:索引长度计算、位示图计算、磁盘调度计算、成组链接法模拟,每个题型先看五道例题,然后自己独立做十道。这个阶段最容易卡住的是成组链接法的流程模拟,因为它不像公式那样一步到位,必须手动走一遍。
时间分配上,如果整个操作系统复习时间是 100,我会给文件管理分 15 到 20。其中概念部分占三分之一,计算部分占三分之二。原因很简单,概念题靠记忆,性价比高但拉不开分;计算题是真正能拉开差距的地方,值得多花时间。
6. 几个容易被忽略的细节补充
6.1 打开文件表和文件描述符
文件系统为了实现"打开"这个操作,维护了两张表:系统级的打开文件表和进程级的打开文件表。进程打开一个文件后,系统会在进程的表里加一项,返回一个文件描述符给用户程序用。之后所有的读写操作都通过这个描述符进行,而不是每次都传文件名。这样做的好处是省掉了重复的路径解析和权限检查。
这个机制在考试里出现得不算高频,但偶尔会以"文件描述符的作用是什么"这种形式出现。我的理解是,它相当于系统给这个打开的文件发了一个编号凭证,后续操作凭号办事。系统表里存的是文件状态、当前读写位置、引用计数等信息,进程表里存的是描述符到系统表项的映射。多个进程打开同一个文件时,系统表里可能只有一项,但引用计数会增加。这个引用计数和硬链接的引用计数不是一回事,前者是打开次数,后者是链接数量,别搞混。
6.2 引导块和坏块处理
磁盘在真正装文件系统之前,要先格式化。格式化之后,磁盘的某个固定位置会放一个引导块,里面是启动系统时要用到的引导代码。这个位置一般不能让普通文件占用,否则系统就起不来了。考试如果问"引导块的作用",答"存放引导程序,用于系统启动"就够了,不用展开太多。
坏块处理有两种思路。一种是保留一部分备用扇区,系统检测到坏块之后,用备用扇区顶替它,并对上层隐藏这个替换,这叫扇区备用。另一种是把坏块标记出来,让文件系统在分配时避开它,这叫扇区稀疏。前者对用户完全透明,后者需要文件系统配合。这两种方法的区别在选择题里出现过,记住"预留替换"和"标记规避"这两个关键词就能区分。
6.3 固态硬盘和机械硬盘的本质差异
固态硬盘是这几年新增的考点,因为它的结构和机械硬盘完全不同。机械硬盘靠盘片旋转和磁头移动定位,所以有寻道和旋转延迟;固态硬盘靠闪存芯片存储,地址定位是电信号完成的,几乎不花时间,所以随机访问速度极快。
但固态硬盘有个天生缺陷:闪存写之前必须先擦除,擦除的最小单位是块,而读写的单位是页。一个块通常包含很多页,如果只想改其中一页,不能直接改,得先把整个块的其他页读出来,擦掉整块,再写回去。这个特征导致写操作比读操作慢得多,也导致擦除次数累积会损耗闪存。为了解决这个问题,固态硬盘内置了闪存翻译层,把上层的逻辑块地址映射到物理页地址,并做磨损均衡,尽量让各个块被均匀擦写,延长整盘寿命。
这些内容看起来偏硬件,但在操作系统课里考的是它们和文件系统的关系。比如问"固态硬盘是否需要磁盘调度算法",答案是不太需要,因为不存在寻道问题;问"固态硬盘的读写不对称体现在哪",答读快写慢,原因是擦除和写入的特性。理解到这一层,这类题就不会慌。
7. 我自己的一些复盘体会
学完这一章,我最大的感受是,文件管理其实是一门"映射的艺术"。用户看到的是名字和目录,系统要处理的是块和指针,中间隔着一层层的转换。逻辑结构、物理结构、目录、索引、位示图、调度算法,本质上都是在处理不同层级之间的映射关系。把这些映射关系想清楚了,公式和结论都是顺带的事;反过来,如果只是背结论,题目一变形就抓瞎。
如果让我给正在复习这一章的人一个建议,那就是别急着刷题,先把每种方法的"为什么"讲给自己听一遍。为什么连续分配会产生外部碎片?为什么隐式链接不支持随机访问?为什么 C-SCAN 比 SCAN 更公平?能把这个"为什么"讲通,碰到没见过的设问也不至于无从下手。
另外,计算题一定要动笔。看例题会让人产生一种"我懂了"的错觉,但真到算位示图那块,字号位号一混就开始怀疑人生。我的做法是每类计算题至少独立做三遍,第一遍照着例题做,第二遍合上答案做,第三遍限时做。三遍下来,手感就稳了。这个笨办法在考场上救过我好几次。