本文已参与「新人创作礼」活动,一起开启掘金创作之路。
文件管理
初识文件管理
文件的属性:
- 文件名
- 标识符
- 类型
- 位置
- 大小
- 创建时间
- 上次修改时间
- 文件所有者信息
- 保护信息
文件数据组织形式:
- 无结构文件(流式文件,如文本文件)
- 有结构文件(记录式文件,如数据库表)
操作系统向上提供的功能:
- 创建文件----create系统调用
- 读文件----read系统调用
- 写文件----write系统调用
- 删除文件----delete系统调用
- 打开文件----open系统调用
- 关闭文件----close系统调用
可用几个基本操作完成更复杂的操作,比如:“复制文件”:
- 先创建一个新的空文件
- 再把源文件读入内存
- 再将内存中的数据写到新文件中
文件在外存中的存储方式
与内存相似,磁盘分为若干小磁盘块,将文件数据连续或离散的存入各磁盘块之间
操作系统需要提供的其他文件管理功能
- 文件共享
- 文件保护
文件的逻辑结构
本节我们重点关注有结构文件:
由一组相似的记录组成,又称“记录式文件”。每条记录又由若干个数据项组成。如:数据库表文件。一般来说,每条记录有一个数据项可作为关键字(作为识别不同记录的ID)
根据各条记录的长度(占用的存储空间)是否相等,又可分为定长记录和变长记录两种。
定长记录↓
可变长记录↓
有结构文件的逻辑结构
**顺序文件:**文件中的记录一个接一个地顺序存储(逻辑上),记录可以是定长的或可变长的。各个记录在物理上可以顺序存储或链式存储。
**索引文件:**建立一张索引表以加快文件检索的速度,每条记录对应一个索引项,记录中的文件在物理上就可以离散地存放
索引表本身是定长记录的顺序文件。因此可以快速找到第i个记录对应的索引项。
可将关键字作为索引号内容,若按关键字顺序排列,则还可以支持按照关键字折半查找。
每当要增加/删除一个记录时,需要对索引表进行修改。由于索引文件有很快的检索速度,因此主要用于对信息处理的及时性要求比较高的场合。
另外,可以用不同的数据项建立多个索引表。如:学生信息表中,可用关键字“学号”建立一张索引表。也可用“姓名”再建立一张索引表。这样就可以根据“姓名”快速地检索文件了。
但这样对存储空间的利用率就会较低
**索引顺序文件:**将索引文件和顺序文件的思想相结合。与索引文件不同的是:并不是每个记录都对应一个索引表项,而是一组记录对应一个索引表项。
左边表是索引表,右边是顺序存储,通过索引找到首字母初地址,再进行顺序查找。
这种存储方式在记录数较少情况下检索速率较快,但记录数多的情形下检索效率依旧不足,所以我们引入多级索引顺序文件👇
文件目录
文件控制块
目录文件----本身就是一种有结构文件,由一条条记录组成。每条记录对应一个放在该目录下的文件👇
目录文件中的一条记录就是一个“文件控制块(FCB)”
FCB的有序集合称为”文件目录“,一个FCB就是一个文件目录项。
FCB中包含了文件的基本信息(文件名、物理地址、逻辑结构等),存取控制信息(是否可读/可写、禁止访问的用户名单等),使用信息(文件的建立时间、修改时间等)。 最重要,最基本的还是文件名、文件存放的物理地址。
FCB实现了文件名和文件之间的映射。使用户(用户程序)可以实现”按名存取“。
需要对目录进行的操作:
- 搜索
- 创建文件
- 删除文件
- 显示目录
- 修改目录
目录结构----单级目录结构
实现了按名存取,但是不允许文件重名
目录结构----两级目录结构
允许不同用户的文件名重名
目录结构----多级目录结构(树形目录结构)
很多时候,用户会连续访问同一目录内的多个文件,显然,每次都从根目录开始查找是很低效的,因此可以设置一个“当前目录”。
树形目录结构可以很方便地对文件进行分类,层次结构清晰,也能够更有效地进行文件的管理和保护。但是,树形结构不便于实现文件的共享。为此,提出了**“无环图目录结构”**
目录结构----无环图目录结构
在树形目录结构的基础上,增加一些指向同一节点的有向边,使整个目录成为一个有向无环图。可以更方便地实现多个用户间的文件共享。
可以用不同的文件名指向同一个文件,甚至可以指向同一个目录(共享同一目录下的所有内容)。
需要为每个结点设置一个共享计数器,用于记录此时有多少个地方在共享该结点。用户提出删除结点请求时,只是删除该用户的FCB、并使共享计数器减1,并不会直接删除共享结点。
索引节点(FCB的改进)
原来的FCB表是这个样子👇
但是在查找中,文件名是主键,所以我们考虑将主键以外的信息均存储到另一个地方(索引结点),在FCB表中只保留索引结点指针来指向该位置,提高查找效率(减少启动磁盘块次数)
存放在外存中的索引结点称为“硬盘索引结点”
放入内存则称为“内存索引结点”
文件的物理结构
操作系统需要对磁盘块进行的管理:
- 对非空闲磁盘块的管理(文件的物理结构/文件分配方式等)
- 对空闲磁盘块的管理
很多操作系统中,磁盘块的大小与内存块、页面的大小相同
内存与磁盘之间的数据交换都是以“块”为单位进行的,即每次读入一块,或每次写出一块。
文件的逻辑地址可以表示为**(逻辑块号,块内地址)**的形式
文件分配方式----连续分配
物理块号 = 起始块号 + 逻辑块号
连续分配支持顺序访问和直接访问(即随机访问)
读取某个磁盘块时,需要移动磁头。访问的两个磁盘块相隔越远,移动磁头所需时间越长
结论:
- 连续分配的文件在顺序读/写时速度最快
- 物理上采用连续分配的文件不方便拓展
- 存储空间利用率低,会产生难以利用的磁盘碎片(可以用紧凑来处理碎片,但会耗费很大的时间代价
文件分配方式----链接分配----隐式链接
先读起始,然后读一个才能知道下一个块在哪里存,故名隐式
结论:
- 只支持顺序访问,不支持随机访问
- 链接分配方式,很方便文件拓展
- 不会有碎片问题,外存利用率高
文件分配方式----连接分配----显式链接
把用于链接文件各物理块的指针显式地存放在一张表中,即文件分配表(FAT)
逻辑块号转换成物理块号的过程不需要读磁盘操作
结论:
- 支持顺序访问,也支持随机访问,块号转换过程并不需要访问磁盘,因此相比于隐式链接来说,访问速度快很多
- 同样不会产生外部碎片,可以很方便地对文件进行拓展
- 缺点是文件分配表需要占用一定的存储空间
文件分配方式----索引分配
索引分配允许文件离散地分配在各个磁盘块中,系统会为每个文件建立一张索引表,索引表中记录了文件的各个逻辑块对应的物理块。索引表存放的磁盘块称为索引块。文件数据存放的磁盘块称为数据块。
总结:
- 可以支持随机访问,文件拓展也很容易实现
- 缺点是索引表需要占用一定的存储空间
如果索引表太大,一个磁盘块装不下,提供三种解决方案:
-
链接方案:如果索引表太大,一个索引块装不下,那么可以将多个索引块链接起来存放 但如果文件太大,索引块太多,使用链接的方式存储,则会导致若要访问最后一个链接块就必须要访问前面的所有逻辑块,这种方式显然很低效
-
为了解决上述问题,我们引出多级索引,建立多层索引(类似于多级页表)。使第一层索引块指向第二层的索引块。还可根据文件大小的要求再建立第三层、第四层索引块。
根据逻辑块号计算表项:
逻辑块号/索引表长度 = 一级索引块号
逻辑块号%索引表长度 = 二级索引表中块内偏移量
文件最大长度 = 索引表长度^索引总层数*内存块大小
采用K层索引结构,且顶级索引表未调入内存,则访问一个数据块只需要K+1次读磁盘操作
-
**混合索引:**多种索引分配方式的结合。例如,一个文件的顶级索引表中,既包含直接地址索引(直接指向数据块),又包含一级间接索引(指向单层索引表)、还包含两级间接索引(指向两层索引表)
文件存储空间管理
存储空间管理----空闲表法
回收时要注意表项的合并问题
存储空间管理----空闲链表法
空闲盘块链
操作系统保存着链头、链尾指针。
**分配:**若某文件申请K个盘块,则从链头开始依次摘下K个盘块分配,并修改空闲链的链头指针。
**回收:**回收的盘块依次挂到链尾,并修改空闲链的链尾指针。
这种分配方式适用于离散分配的物理结构。为文件分配多个盘块时可能要重复多次操作。
空闲盘区链
操作系统保存着链头、链尾指针。
**分配:**若某文件申请K个盘块,则可以采用首次适应、最佳适应算法,从链头开始检索,按照算法规则找到一个大小符合要求的空闲盘区,分配给文件。若没有合适的连续空闲块,也可以将不同盘区的盘块同时分配给一个文件,注意分配后可能要修改相应的链指针、盘区大小等数据。
**回收:**若回收区和某个空闲盘区相邻,则需要将回收区合并到空闲盘区中。若回收区没有和任何空闲区相邻,将回收区作为单独的一个空闲盘区挂到链尾。
离散分配、连续分配都适用。为一个文件分配多个盘块时效率更高。
存储空间管理----位示图法
每个二进制位对应一个盘块,"0"代表盘块空闲,"1"代表盘块已分配。位示图一般用连续的“字”来表示,如本例中一个字的字长是16位,字中的每一位对应一个盘块。因此可以用(字号,位号)对应一个盘块号。
转换计算:(字号,位号)= (i,j)的二进制位对应的盘块号b = ni + j
b号盘块对应的字号i = b/n,位号j = b%n
存储空间管理----成组链接法
空闲表法、空闲链表法不适用于大型文件系统,因为空闲表或空闲链表可能过大。UNIX系统中采用了成组链接法对磁盘空闲块进行管理。
文件卷的目录区中专门用一个磁盘块作为“超级块”,当系统启动时需要将超级块读入内存。并且要保证内存与外存中的“超级块”数据一致。