操作系统 第四章 文件管理
🚥操作系统 系列文章导航🚥
一、文件系统基础
1.文件的基本概念
文件(File) 是以硬盘为载体的存储在计算机上的信息集合,可以是文本文档、图片、程序等。
在系统运行时,计算机以进程为单位进行资源的调度和分配;而在用户进行的输入输出中,则以文件为基本单位。
当用于将文件用于程序的输入输出时,还希望可以访问、修改和保存文件等,操作系统中的文件系统(File System) 用于实现这些管理要求。
文件分为两种:
-
有结构文件:由若干个相似的记录组成,又称记录式文件。
-
无结构文件:由一些二进制或字符流组成,又称流式文件。
记录:是一组相关数据项的集合。
数据项:是文件系统中最低级的数据组织形式,分为两种:
-
基本数据项:用于描述一个对象的某种属性的一个值,是数据中的最小逻辑单元。
-
组合数据项:由多个基本数据项组成。
2.文件的属性
除了文件数据,操作系统还会保存与文件相关的信息,这些信息称为文件属性或文件元数据。文件属性在不同系统中差别很大,但通常包括以下属性:
-
名称:文件名称唯一,以容易读取的形式保存(同一目录下不允许有重名文件)。
-
类型:指明文件的类型,被支持不同类型的文件系统所使用。
-
创建者:文件创建者的 ID。
-
所有者:文件当前所有者的 ID。
-
位置:指向设备和设备上文件的指针。
-
大小:文件当前大小
-
保护:对文件进行保护的访问控制信息。
-
创建时间、最后一次修改时间和最后一次存取时间:文件创建、上次修改和上次访问的相关信息,用于保护和跟踪文件的使用。
操作系统通过文件控制块来维护文件元数据。
3.操作系统提供的功能
操作系统向上提供的基本功能:
-
创建文件:creat 系统调用
-
删除文件:delete 系统调用
-
读文件:read 系统调用,将文件数据从外存读入内存,并显示在屏幕上
-
写文件:write 系统调用,将文件数据从内存写回外存
-
打开文件:open 系统调用(读/写文件之前,需要打开文件)
-
关闭文件:close 系统调用(读/写文件之后,需要关闭文件)
可用几个基本操作完成更复杂的操作,比如复制文件:先创建一个新的空文件,再把源文件读入内存,再将内存中的数据写到新文件中。
此外操作系统还会提供其他的文件管理功能:
-
文件共享:使多个用户可以共享使用一个文件。
-
文件保护:保证不同的用户对文件有不同的操作权限。
4.文件的逻辑结构
文件的逻辑结构指从用户角度出发所看到的文件的组织形式。而文件的物理结构(也称存储结构)是指将文件存储在外村上的存储组织形式,是用户所看不见的。
按逻辑结构,文件划分为无结构文件和有结构文件两大类。无结构文件没有结构,因此对记录的访问只能通过穷举搜索的方式。
有结构文件是指由一个以上的记录构成的文件,根据各记录的长度是否相同,可分为定长记录和变长记录两种:
-
定长记录:文件中所有记录的长度都是相同的,各数据项都在记录中的相同位置,具有相同的长度。检索记录的速度快,方便用户对文件进行处理,广泛用于数据处理中。
-
变长记录:文件中各记录的长度不一定相同,原因可能是记录中所包含的数据项数目不同,也可能是数据项本身的长度不定。检索记录只能顺序查找,速度慢。
有结构文件按记录的形式可以分为顺序文件、索引文件、索引顺序文件。
(1)顺序文件
顺序文件:文件中的记录一个接一个地顺序排列(逻辑上),记录可以是定长的或可变长的。各个记录在物理上可以顺序存储或链式存储。
顺序文件中记录的排列有两种结构:
-
串结构:各记录之间的顺序与关键字无关,通常是按存入的先后时间进行排列,检索时必须从头开始顺序依次查找,比较费时。
-
顺序结构:所有记录按关键字顺序排列,对于定长记录的顺序文件,检索时可采用折半查找,效率高。
在对记录进行批量操作,即每次需要读或写一大批记录时,顺序文件的效率是所有逻辑文件中最高的。此外,对于顺序存储设备(如磁带),也只有顺序文件才能被存储并能有效地工作。在经常需要增删改查单个记录的场合,顺序文件的性能较差。
注意:一般来说,题目中所说的顺序文件指的是物理上顺序存储的顺序文件。顺序文件的缺点是增删单个记录比较困难,如果是串结构则相对简单。
定长记录的顺序文件,若物理上采用顺序存储,则可实现随机存取;若能再保证记录的顺序结构,则可实现快速检索(即根据关键字快速找到对应记录)。
(2)索引文件
对于变长记录的顺序文件,要查找第 i 条记录,必须顺序地查找前 i-1 条记录,以获得相应记录的长度,进而计算出第 i 条记录的地址。
由于变长记录的顺序文件只能顺序查找,且效率较低。因此,可建立一张索引表,为主文件的每个记录在索引表中分别设置一个索引表项,其中包含指向记录的指针和记录长度。索引表按关键字排序,因此其本身是一个定长记录的顺序文件。

由于索引文件有很快的检索速度,且增加了存储开销,因此主要用于对信息处理的及时性要求比较高的场合。
另外可以用不同的数据项建立多个索引表。如学生信息表中,可以用关键字 “学号” 建立一张索引表,也可以用 “姓名” 建立一张索引表。
(3)索引顺序文件
索引顺序文件先将变长记录顺序文件中的所有记录分为若干组,然后为文件建立一张索引表,并为每组中的第一个记录建立一个索引项,其中包含该记录的关键字和指向该记录的指针。
同一个组内的关键字可以无序,但组与组之间的关键字必须有序。
检索时,先查找索引表,找该记录所在的组,然后在该组中使用顺序查找,就能很快地找到记录。
为了进一步提高检索效率,可以为顺序文件建立多级索引表:

(4)直接文件或散列文件(Hash File)
给定记录的键值或通过散列函数转换的键值直接决定记录的物理地址,散列文件具有很高的存取速度,但是会引起冲突,即不同的关键字的散列函数值可能相同。
实际上,有结构文件逻辑上的组织,是为在文件中查找数据服务的(顺序查找、索引查找、索引顺序查找、哈希查找)。
5.文件的物理结构(文件分配方式)
类似于内存分页,磁盘中的存储单元也会被分为一个个块/磁盘块/物理块。很多操作系统中,磁盘块的大小与内存块、页面的大小相同。内存与磁盘间的数据交换(即读/写操作,磁盘 I/O)都是以块为单位进行的。
在外存管理中, 文件的逻辑地址空间也被分为了一个个文件块。于是文件的逻辑地址也可以表示为(逻辑块号,块内地址)的形式。
操作系统为文件分配存储空间都是以块为单位的。用户通过逻辑地址来操作自己的文件,操作系统要负责实现从逻辑地址到物理地址的映射。
(1)连续分配
连续分配:要求每个文件在磁盘上占有一组连续的块。

采用连续分配时,逻辑文件中的记录也顺序存储在相邻的物理块中。一个文件的目录项中记录其存放的起始块号和长度(总共占用几个块):

用户给出要访问的逻辑块号,操作系统找到该文件对应的目录项(FCB),物理块号 = 起始块号 + 逻辑块号(需要检查逻辑块号是否合法,如果逻辑块号 >= 长度就不合法)。因为可以直接计算出逻辑块号对应的物理块号,因此连续分配支持顺序访问和直接访问(即随机访问)。
连续分配方式下,进程访问磁盘时需要的寻道数和寻道时间最小,顺序读/写时速度最快。
缺点:①存储空间利用率低,会产生很多外部碎片。可以用紧凑来处理碎片,但需要耗费很大的时间代价。②必须事先知道文件的长度,也无法满足文件动态增长的需求,否则会覆盖物理上相邻的后续文件。③为保持文件的有序性,删除和插入记录时,需要对相邻的记录做物理上的移动。
(2)链接分配
链接分配:采取离散分配的方式,可以为文件分配离散的磁盘块。分为隐式链接和显式链接两种。
①隐式链接

想要读入 i 号逻辑块,需要先把第 0 块读入内存,然后依次找到下一块的物理块号,总共需要 i + 1 次磁盘 I/O。
优点:①采用链接分配方式,方便文件拓展。②所有的空闲磁盘块都可以被利用,不会有碎片问题,外存利用率高。
缺点:①只支持顺序访问,随机访问效率很低。②稳定性问题,文件盘块中的任何一个指针出问题,都会找到文件数据的丢失。③指向下一个盘块的指针也要耗费一定的存储空间。
文件空间与簇的关系
为了提高查找速度,减少指针所占用的存储空间,可以将几个盘块组成一个簇,按簇而不按块来分配,可以大幅地减少查找时间,也可以改善许多算法的磁盘访问时间。比如一簇为 4 块,这样,指针所占的磁盘空间比例也要小得多。这种方法的代价是增加了内部碎片。
②显式链接
显式链接是指将用于链接文件各物理块的指针显式地存放在一张表中。即文件分配表(FAT,File Allocation Table)。
目录中只需记录文件的起始块号,后续块号可以通过查找 FAT 找到(-1表示该块为文件的结尾):

注意:一个磁盘仅设置一张 FAT。开机时,将 FAT 读入内存,并常驻内存。FAT 的各个表项在物理上连续存储,且每一个表项长度相同,因此物理块号字段可以是隐含的。
用户给出要访问的逻辑块号 i,操作系统找到该文件对应的目录项(FCB),若 i > 0,则查找内存中的文件分配表 FAT。逻辑块号转换到物理块号的过程不需要读磁盘操作。
优点:①支持顺序访问,也支持直接访问,要访问第 i 块,无需访问前 i - 1 块。②FAT 在系统启动时就被读入内存,检索记录是在内存中进行的,因此不仅显著提高了检索速度,还明显减少了访问磁盘的次数。
缺点:FAT 需要占用一定的内存空间。
注意:考试中若未指明隐式/显式的链接分配,默认指的是隐式链接分配。
(3)索引分配
索引分配:允许文件离散地分配在各个磁盘块中,系统会为每个文件建立一张索引表,索引表中记录了文件的各个逻辑块对应的物理块。索引表存放的磁盘块称为索引块,文件数据存放的磁盘块称为数据块。
下图为一个文件的索引表:

可以用固定的长 度表示物理块号,因此索引表中的逻辑块号可以是隐含的。
采用索引分配方式的文件需要再自己的目录项(FCB)中记录自己的索引块:
优点:①索引分配方式可以支持随机访问。②不会产生外部碎片。③文件拓展也很容易实现(只需要给文件分配一个空闲块,并增加一个索引表项即可)。
缺点:索引块增加了额外的存储空间开销。
注意:显式链接方式中,文件分配表 FAT 是一个磁盘对应一张,使用时需要把整个 FAT 都调入内存。而索引分配方式中,索引表是一个文件对应一张。
当一个文件过大,一个磁盘块装不下该文件的整张索引表时,有以下三种解决方式:
①链接方案:如果索引表太大,一个索引块装不下,那么可以将多个索引块链接起来存放。

需要先把第一个索引块读入内存,才能根据指针找到第二个索引块。当链接的索引块过多时,需要多次读取磁盘,过于低效。
②多层索引:建立多层索引(原理类似于多级页表)。使第一层索引块指向第二层的索引块。还可根据文件大小的要求再建立第三层、第四层索引块。

采用 K 层索引结构,且顶级索引表未调入内存,则访问一个数据块只需要 K + 1 次读磁盘操作。
优点:极大加快了对大型文件的查找速度。
缺点:当访问一个盘块时,其所需启动磁盘的次数随着索引级数的增加而增多,即使是对数量众多的小文件也是如此。
③混合索引:多种索引分配方式的结合。例如,一个文件的顶级索引表中,既包含直接地址索引(直接指向数据块),又包含一级间接索引(指向单层索引表),还包含两级间接索引(指向两层索引表)。
二、文件目录
1.文件控制块
下图是为一个根目录(D:盘)的目录文件:

目录本身就是一种有结构文件,由一条条记录组成。每条记录对应一个放在该目录下的文件。
当我们在电脑上双击 “照片” 后,操作系统会在这个目录表中找到关键字 “照片” 对应的目录项(也就是记录),然后从外存中将 “照片” 目录的信息读入内存,于是,“照片” 目录中的内容就可以显示出来了。
目录文件中的一条记录就是一个文件控制块(FCB)。FCB 的有序集合称为文件目录。
FCB 中包含了文件的以下信息:
-
基本信息:如文件名、文件的物理位置、文件的逻辑结构、文件的物理结构等。
-
存取控制信息:包括文件主的存取权限,核准用户的存取权限以及一般用户的存取权限。
-
使用信息:如文件建立时间、上次修改时间等。
最重要,最基本的还是文件名和文件存放的物理地址。因为 FCB 实现了文件名和文件之间的映射,使用户(用户程序)可以实现按名存取。
对目录进行的操作:
-
搜索:当用户要使用一个文件时,系统要根据文件名搜索目录,找到该文件对应的目录项。
-
创建文件:创建一个新文件时,需要在其所属的目录中增加一个目录项。
-
删除文件:当删除一个文件时,需要在目录中删除相应的目录项。
-
创建目录:在树形目录结构中,用户可创建自己的用户目录文件,并可再创建子目录。
-
删除目录:有两种方式①不删除非空目录,删除时要先删除目录中的所有文件,并递归地删除子目录。②可删除非空目录,目录中的文件和子目录同时被删除。
-
显示目录:用户可以请求显示目录的内容,如显示该目录中的所有文件及相应属性。
-
修改目录:某些文件属性保存在目录中,因此这些属性变化时需要修改相应的目录项(如文件重命名)。
-
移动目录:将文件或子目录在不同的父目录之间移动,文件的路径名也会随之改变。
2.目录结构
(1)单级目录结构
在整个文件系统中只有一张目录表,每个文件占一个目录项。

在创建一个文件时,需要先检查目录表中有没有重名文件,确定不重名后才能允许建立文件,并将新文件对应的目录项插入目录表中。当删除一个文件时,先从该目录中找到该文件的目录项,回收该文件所占用的存储空间,然后清除该目录项。
单级目录结构实现了 “按名存取”,但是存在查找速度慢、文件不允许重名、不便于文件共享等缺点,不适用于多用户操作系统。
(2)两级目录结构
两级方案,将文件目录分成主文件目录(Master File Directory,MFD) 和用户文件目录(User File Directory,UFD) 两级:

MFD 记录用户名及相应用户文件目录所在的存储位置,UFD 记录该用户所有文件的 FCB。
两级目录结构提高了检索的速度,解决了多用户之间的文件重名问题,文件系统可以在目录上实现访问限制。但是两级目录缺乏灵活性,不能对文件分类。
(3)树形目录结构
两级目录结构加以推广,就形成了树形目录结构:

用户(或用户进程)要访问某个文件时,要用文件路径名标识文件,文件路径名是个字符串。各级目录之间用 “/” 隔开。从根目录出发的路径称为绝对路径。
系统根据绝对路径一层层地找到下一级目录。以 “/照片/2015-08/自拍.jpg” 为例。刚开始从外存读入根目录的目录表;找到 “照片” 目录的存放位置后,从外存读入对应的目录表;再找到 “2015-08” 目录的存放位置,再从外存读入对应目录表;最后才找到文件 “自拍.jpg” 的存放位置。整个过程需要 3 次 读磁盘 I/O 操作。
每次都从跟目录查询过于低效。因此可以设置一个当前目录。
例如,此时已经打开了 “照片” 的目录文件,也就是说,这张目录表已调入内存,那么可以把它设置为当前目前。当用户想要访问某个文件时,可以使用从当前目录出发的相对路径。
在 Linux 中,“.” 表示当前目录。因此如果 “照片” 是当前目录,则 “自拍.jpg” 的相对路径为:“./2015-08/自拍.jpg”。
树形目录结构可以很方便地对文件进行分类,层次结构清晰,也能更有效地进行文件的管理和保护。但是,树形结构不便于实现文件的共享。为此,提出了无环图目录结构。
(4)无环图目录结构
无环图目录结构在树形目录结构的基础上,增加一些指向同一节点的有向边,使整个目录成为一个有向无环图。

可以用不同的文件名指向同一个文件,甚至可以指向同一个目录(共享同一目录下的所有内容)。
需要为每个共享结点设置一个共享计数器,用于记录此时有多少个地方在共享该节点。用户提出删除节点的请求时,只是删除该用户的 FCB、并使共享计数器减 1,并不会直接删除共享结点。只有共享计数器减为 0 时,才删除结点。
注意:共享文件不同于复制文件。在共享文件中,由于各用户指向的是同一个文件,因此只要其中一个用户修改了文件数据,那么所有的用户都可以看到文件数据的变化。
3.索引节点(FCB 的改进)
在索引目录的过程中,只用到了文件名,只有文件名匹配时,才需要读出文件的其他信息。因此有的系统采用了文件名和文件描述信息分离的方法,使文件描述信息单独形成一个称为索引节点的数据结构,简称 i 结点(inode)。在文件目录中的每个目录项仅由文件名和相应的索引节点号(或索引节点指针)构成。

对目录表 “瘦身” 后,使得查找文件的平均启动磁盘次数减少,大大节省了系统开销,提升了文件检索速度。
磁盘索引节点,指存放在磁盘上的索引节点。每个文件都有一个唯一的磁盘索引节点。注意包括以下内容:
-
文件主标识符
-
文件类型
-
文件存取权限
-
文件物理地址
-
文件长度
-
文件链接计数,在本文件系统中所有指向该文件的文件名的指针计数。
-
文件存取时间,本文件最近被进程存取、修改的时间及索引节点最近被修改的时间。
内存索引节点,指存放在内存中的索引节点,当文件被打开时,要将磁盘索引节点复制到内存的索引节点中,便于以后使用。在内存索引节点中增加了以下内容:
-
索引节点号,用于标识内存索引节点。
-
状态,指示 i 结点是否上锁或被修改。
-
访问计数,每当有一进程要访问此 i 结点时,计数加 1;访问结束减 1。
-
逻辑设备号,文件所属文件系统的逻辑设备号。
-
链接指针,设置分别指向空闲列表和散列队列的指针。
三、文件存储空间管理
存储空间的划分与初始化:
卷可以是磁盘的一部分,也可以是整个磁盘,还可以是多个磁盘组成 RAID 集。每个卷被划分为目录区和文件区。
文件存储设备分成许多大小相同的物理块,并以块为单位交换信息,因此文件存储设备的管理实质上是对空闲块的组织和管理,它包括空闲块的组织、分配与回收等问题。
1.空闲表法
空闲表法属于连续分配方式。系统为外存上的索引空闲区建立一张空闲表,每个空闲区对应一个空闲表项,按其起始盘块号递增的次序排列:

盘块的分配:与内存的动态分配类似,为一个文件分配连续的存储空间,也是采用首次使用算法,最佳适应算法等。例如,在系统为某新创建的文件分配空闲盘块时,先顺序地检索空闲盘块表的各表项,直至找到第一个大小能满足要求的空闲区,再将该盘区分配给用户,同时修改空闲盘块表。
盘块的回收:也采用类似于内存回收的方法,即要考虑回收区是否与空闲盘块表中插入的点的前区和后区相邻接,对相邻接者应予以合并。
2.空闲链表法
空闲链表法可分为两种:
-
空闲盘块链:以盘块为单位组成一条空闲链
-
空闲盘区链:以盘区为单位组成一条空闲链
3.位示图法
位示图:每个二进制位对应一个盘块。0 代表盘块空闲,1 代表盘块已分配。
位示图一般用一个连续的字来表示,如下图中一个字的字长是 16 位。因此可以用(字号,位号)对应一个盘块号。有些地方也描述为(行号,列号)。

注意:在计算盘块号与(字号,位号)的转换时,要注意盘块号、字号、位号是从 0 开始还是从 1 开始。
盘块的分配:若文件需要 K 个块,①顺序扫描位示图,找到 K 个相邻或不相邻的 0;②根据字号、位号算出对应的盘块号,将相应盘块分配给文件;③将相应位设置为 1。
盘块的回收:①根据回收的盘块号计算出对应的字号、位号;②将相应二进制位设为 0。
优点:①位示图法对连续分配和离散分配都适用。②位示图很小,占用空间少,因此可将它保存在内存中,从而节省许多磁盘启动的开销。
缺点:位示图的大小会随着磁盘容量的增大而增大,因此长适用于小型计算机。
4.成组链接法
UNIX 系统中采用成组链接法对磁盘空闲块进行管理。结合了空闲表法和空闲链表法的思想 ,克服了大型文件系统中 “表太长” 的问题。
文件卷的目录区中专门用一个磁盘块作为超级块,当系统启动时需要将超级块读入内存,并且要保证内存与外存中的超级块数据一致。
超级块中记录了下一组空闲盘块的数量,以及这些盘块的盘块号。通过这些盘块号就可以找到下一个分组的各个盘块。每组的第一个盘块还会记录下一组空闲盘块的数量和盘块号。

注意:最后一个分组的盘块数是要比其他分组更少的。
盘块的分配:
如果分配 1 个空闲块,则先检查第一个分组的块数是否足够。1 < 100,因此是足够的。然后分配第一个分组中的一个空闲块,并修改相应数据。

如果分配 100 个空闲块,先检查第一个分组的块数是否足够。100 = 100,是足够的。然后分配第一个分组中的 100 个空闲块。但是由于 300 号块内存放了再下一组的信息,因此 300 号块中的数据需要复制到超级块中。

空闲块的回收:
如果第一个分组空闲块未满,则直接存入空闲块号并修改空闲盘块数即可。
如果第一个分组空闲块已满,还需要再回收一块。需要将超级块中的数据复制到新回收的块中,并修改超级块的内存,让新回收的块成为第一个分组。

注意:26 版王道纸质书上对空闲块的分配和回收是用栈和指针的方式描述的,似乎更好一点,体现出了对顺序的要求。
四、操作系统提供的功能
1.基本功能
(1)创建文件
进行 creat 系统调用时,需要提供几个主要参数:
-
所需的外存空间大小
-
文件存放路径
-
文件名
操作系统进行的操作:
-
在外存中找到文件所需的空间(通过后面讲到的空闲表法、空闲链表法等找到空闲空间)。
-
根据文件存放路径的信息找到该目录对应的目录文件,在目录中创建该文件对应的目录项。
(2)删除文件
进行 delete 系统调用时,需要提供几个主要参数:
-
文件存放路径
-
文件名
操作系统进行的操作:
-
根据文件存放路径找到相应的目录文件,从目录中找到文件名对应的目录项。
-
根据该目录项记录的文件在外存的存放位置、文件大小等信息,回收文件占用的磁盘块。
-
从目录表中删除文件对应的目录项。
(3)打开文件
进行 open 系统调用时,需要提供几个主要参数:
-
文件存放路径
-
文件名
-
要对文件的操作类型(如:r 只读;rw 读写等)
操作系统进行的操作:
-
根据文件存放路径找到相应的目录文件,从目录中找到文件名对应的目录项,并检查该用户是否有指定的操作权限。
-
将目录项复制到内存中的打开文件表中。并将对应表目的索引号(也称文件描述符)返回给用户。之后用户使用打开文件表的编号来指明要操作的文件(节省了大量的检索开销)。

打开文件表有两种,整个系统表和每个进程表:
-
进程打开文件表特有的属性:读写指针、访问权限
-
系统打开文件表特有的属性:打开计数器
注意:文件名不必是打开文件表的一部分,一旦完成对 FCB 在磁盘上的定位,系统就不再使用文件名。对于访问打开文件表的索引号,UNIX 称之为文件描述符,而 WIndows 称之为文件句柄。只要完成了文件的 open() 系统调用,后面再使用 read()、write、Lseek、close() 等文件操作的系统调用,就不再使用文件名,而使用文件描述符,直到文件被关闭。
(4)关闭文件
进程使用完文件后,需要关闭文件。
操作系统在处理 close 系统调用时,主要进行以下操作:
-
将进程的打开文件表相应表项删除。
-
回收分配给该文件的内存空间等资源。
-
系统打开文件表的打开计数器 count 减 1,若 count = 0,则删除对应表项。
(5)读文件和写文件
读/写文件时,用文件描述符即可指明文件,不再需要用到文件名。
-
读文件:根据读指针、读入数据量、内存位置将数据从外存读入内存。
-
写文件:根据写指针、写出数据量、内存位置将数据从内存写出外出。
2.文件共享
操作系统为用户提供文件共享功能,可以让多个用户共享地使用同一个文件。系统中只需要保存一个该文件的副本,其中一个用户修改了该文件的数据,其他用户也可以看到文件数据的变化。
(1)基于索引节点的共享方式(硬链接)
索引节点是前面讲到的一种文件目录瘦身策略。由于检索文件时只需用到文件名,因此可以将除了文件名之外的其他信息放到索引节点中。这样目录项就只需要包含文件名、索引结点指针。
不同用户给同一个文件起的文件名可以是不同的。
只有当 count = 0 时,系统才会删除文件,否则会导致指针悬空。
(2)基于符号链的共享方式(软链接)
当 User3 访问 ccc 时,操作系统判断文件 ccc 属于 Link 类型文件,于是会根据其中记录的路径层层查找目录,最终找到 User1 的目录表中的 aaa 表项,于是就找到了文件 1 的索引结点
由于用软链接的方式访问共享文件时要查询多级目录,会有多次磁盘 I/O。因此,硬链接的查找速度要比软链接的快。
3.文件保护
保护文件数据的安全可以通过口令保护、加密保护、访问控制等方式实现。
(1)口令保护
口令保护:为文件设置一个口令,如:“2333”,用户请求访问该文件时必须提供口令。口令一般存放在文件对应的 FCB 或索引结点中。
优点:保存口令的空间开销不多,验证口令的时间开销也很小。
缺点:正确的口令存放在系统内部,不够安全。
(2)加密保护
加密保护:使用某个密码对文件进行加密,在访问文件时需要提供正确的密码才能对文件进行正确的解密。
优点:保密性强,不需要在系统中存储密码。
缺点:编码/译码,或者说加密/解密要花费一定时间。
(3)访问控制
访问控制:在每个文件的 FCB 或索引结点中增加一个访问控制列表(Access-Control List,ACL),该表中记录了各个用户可以对该文件执行哪些操作。
访问类型:
-
读:从文件中读数据
-
写:向文件中写数据
-
执行:将文件装入内存并执行
-
添加:将新信息添加到文件结尾部分
-
删除:删除文件,释放空间
-
列表清单:列出文件名和文件属性
此外还可以对文件的重命名、复制、编辑等加以控制。这些高层的功能可以通过系统程序调用低层系统调用来实现。保护可以只在低层提供。例如,复制文件可利用一系列的读请求来完成,这样,具有读访问权限的用户同时也就具有了复制和打印权限。
下图为一个 ACL 示例:

有的计算机可能会有多个用户,因此 ACL 可能会很大,可以用精简的 ACL 解决这个问题。
精简的访问控制列表:以组为单位,标记各组用户可以对文件执行哪些操作。当某用户想要访问文件时,系统会检查该用户所属的分组是否有相应的访问权限(系统需要管理分组信息)。
例如可以采用拥有者、组、和其他三种用户类型:
-
拥有者:创建文件的用户
-
组:一组需要共享文件且具有类似访问的用户
-
其他:系统内的所有其他用户
五、文件系统
1.文件系统结构
文件系统的层次结构:
以用户请求删除文件 “D:/工作记录/学生信息.xlsx” 的最后 100 条记录为例:
-
用户需要通过操作系统提供的接口发出上述请求——用户接口
-
由于用户提供的是文件的存放路径,因此需要操作系统需要一层一层地查找目录,找到对应的目录项——文件目录系统
-
不同的用户对文件有不同的操作权限,因此为了保证安全,需要检查用户是否有权限访问——存取控制模块
-
验证了用户的访问权限之后,需要把用户提供的 “记录号” 转变为对应的逻辑地址——逻辑文件系统与文件信息缓冲区
-
知道了目标记录对应的逻辑地址后,还需要转换成实际的物理地址——物理文件系统
-
要删除这些记录,必定要对磁盘设备发出请求——设备管理程序模块
-
删除这些记录后,会有一些盘块空闲,因此要将这些空闲盘块回收——辅助分配模块
注意:现代操作系统的文件系统层次结构不尽相同,王道纸质书上给出的是另一种结构。
2.文件系统布局
(1)文件系统在外存中的结构
物理格式化:即低级格式化,划分扇区,检测坏扇区,并用备用扇区替换坏扇区。坏扇区的存在对操作系统来说是透明的。
逻辑格式化:对原始磁盘进行物理格式化后,需要再进行逻辑格式化,即高级格式化,磁盘分区(分卷 Volume)。完成对各分区的文件系统初始化。
注意:逻辑格式化后,灰色部分就有实际数据了,白色部分还没有数据。
(2)文件系统在内存中的结构
近期访问过的目录文件会缓存在内存中,不用每次都从磁盘读入,这样可以加快目录检索速度。
3.虚拟文件系统
虚拟文件系统(VFS) 屏蔽了不同文件系统的差异和操作细节,①向上为用户提供了文件操作的统一调用接口。VFS 采用面向对象的方法,抽象出一个通用的文件系统模型,定义了通用文件系统都支持的接口。②只有支持并实现了这些接口的文件系统才能被该 VFS 兼容。

由于不同文件系统中的存储的信息格式不不同。因此③每打开一个文件,VFS 就在主存中新建一个 vnode,用统一的数据结构表示文件,无论该文件存储在哪个文件系统。

不同文件系统实现 VFS 规定的各种函数功能的具体代码是各部相同的,因此 v 结点中的函数功能指针指向各自文件系统对应的函数功能列表。

注意:vnode 只存在于主存中,而 inode 既会被调入主存,也会在外存中存储。
4.文件系统挂载
文件系统挂载(mounting),即文件系统的安装/挂载。指如何将一个文件系统挂载到操作系统中。
具体操作:
-
在 VFS 中注册新挂载的文件系统。内存中的**挂载表(mount table)**包含每个文件系统的相关信息,包括文件系统类型、容量大小等。
-
新挂载的文件系统,要向 VFS 提供一个函数地址列表。
-
将新文件系统加到挂载点(mount point),也就是将新文件系统挂载在某个父目录下。