操作系统-文件管理
8.1 文件和文件系统
文件管理这一章看起来零碎,实际上围绕的是一个很统一的问题:操作系统怎样把外存上的数据组织成“用户能按名字访问、系统能高效管理”的形式。文件、目录、FCB、索引节点、保护机制,本质上都在服务这个目标。
文件、记录和数据项
文件内部常按三级层次来理解:
- 数据项:最基本的数据组织单位。可以分为基本数据项和组合数据项
- 记录:一组相关数据项的集合,其中关键字段可唯一标识一条记录
- 文件:由创建者定义的相关信息集合,在逻辑上具有结构,也是逻辑外存的最小分配单位
这个层次关系很重要,因为后面说“有结构文件”“记录式文件”“关键字检索”时,本质上都建立在记录和数据项之上。
文件名和文件类型
- 文件名:用户通过文件名访问文件,而操作系统内部通常通过 FCB 管理文件
- 文件类型:
- 普通文件:文本文件、二进制文件、可执行文件等
- 目录文件:专门用于管理其他文件
- 特殊文件:设备文件,例如 Unix 中的块设备和字符设备
文件系统
文件系统的定义
文件系统通常可以从三个层面理解:
- 对象及其属性:文件、目录、磁盘空间,以及它们对应的管理信息
- 软件集合:负责管理这些对象的软件模块
- 接口:对用户和进程提供文件操作接口
也就是说,文件系统不只是“磁盘上的目录树”,而是一整套从数据组织到访问接口的管理机制。
文件系统的层次结构
自底向上通常可分为五层:
- I/O 控制层:设备驱动、中断处理、数据传送
- 基本文件系统:直接与设备驱动通信,处理磁盘块读写
- 基本 I/O 管理程序:完成文件逻辑块号到物理块号的转换
- 逻辑文件系统:管理 FCB、目录、存储空间等元数据
- 用户 / 应用层:通过系统调用访问文件系统
这种分层思路和 I/O 系统分层很像,目的都是把上层的“按名访问”与底层的“按块读写”隔开。
文件操作
文件操作里最基础的是 6 个:
| 操作 | 说明 |
|---|---|
Create |
分配 FCB 并分配存储空间 |
Delete |
释放空间并删除 FCB |
Open |
把 FCB 读入内存打开文件表,返回文件描述符 |
Close |
释放内存表项,并把修改后的 FCB 写回磁盘 |
Read |
从读指针位置读数据,并推进指针 |
Write |
从写指针位置写数据,并推进指针 |
Open 和 Close 的意义尤其常考:
Open的关键不是“宣布文件打开”,而是把磁盘上的文件控制信息调入内存,后续读写就不必每次都查盘Close也不只是“关掉文件”,还包括把内存中被修改过的控制信息写回磁盘
此外还常见:
AppendSeekRenameGet / Set Attributes
8.2 文件的逻辑结构
文件的逻辑结构说的是:从用户和应用程序视角看,文件内部的数据是按什么方式组织的。它强调的是“逻辑上的排列方式”,不等于磁盘上的物理存放方式。
文件逻辑结构的类型
按文件是否有结构来分:
- 有结构文件:由若干相关记录组成,又称记录式文件
- 无结构文件:由字符流或字节流构成,又称流式文件,例如文本文件、源程序文件
按组织方式来分:
- 顺序文件
- 索引文件
- 索引顺序文件
顺序文件
- 顺序文件:文件中的记录按某种顺序排列而成
- 排列方式有两种:
- 串结构:记录顺序与关键字无关,通常按存入时间排列
- 顺序结构:记录按关键字次序排列
顺序文件的优点是结构简单、适合顺序存取、批处理效率高。若采用顺序结构,按关键字查找也会更方便。
顺序文件记录寻址
- 隐式寻址:只能按顺序逐个找记录,多用于串结构
- 显式寻址:可直接给出记录号访问记录,多用于定长记录文件
索引文件
- 索引文件:为文件建立索引表,索引表中记录关键字和记录地址
- 查找时可以先查索引,再直接定位到对应记录
- 如果要按多个关键字检索,可以建立多个索引表
它的核心优势是检索快,但代价是需要额外维护索引。
索引顺序文件
- 索引顺序文件:把顺序文件和索引文件结合起来
- 基本思路是先把记录分组、组内顺序存放,再对每组建立索引项
常见形式:
- 一级索引顺序文件:只建立一层组索引
- 两级索引顺序文件:文件更大时,再对一级索引表建立索引
直接文件和哈希文件
- 直接文件:根据关键字可直接定位记录位置
- 哈希文件:通过哈希函数把关键字转换成地址
哈希文件查找速度快,但不同关键字可能映射到同一地址,因此会产生冲突问题。
8.3 文件目录
如果说文件逻辑结构解决的是“文件内部怎么组织”,那文件目录解决的就是“用户怎样按名字找到文件”。目录本质上是一种特殊的管理数据结构。
文件控制块和索引节点
- FCB:文件控制块,是文件存在的标志,通常记录文件名、类型、物理地址、长度、存取控制信息、建立时间等
- 索引节点:把文件名和文件描述信息分开存放,目录项中主要保留文件名和索引节点号,其余信息放入索引节点
引入索引节点的主要目的,是缩短目录项长度、提高目录检索效率。
简单的文件目录
- 单级文件目录:整个文件系统只有一张目录表,实现简单,但不允许文件重名,也不适合多用户系统
- 两级文件目录:分为主文件目录和用户文件目录,允许不同用户的文件重名,但同一用户的文件仍不能重名
这两种结构都比较简单,能帮助理解目录系统为什么会继续演进。
树形目录
- 树形目录:把各级目录组织成一棵树,根目录在最上层,子目录和文件作为分支
- 优点是层次清楚、便于分类管理,现代文件系统大多采用这种思路
与树形目录配套的概念包括:
- 绝对路径:从根目录出发的路径
- 相对路径:从当前目录出发的路径
- 当前目录:用户当前工作的目录
常见目录操作有:
- 创建目录
- 删除目录
- 改变当前目录
- 显示目录内容
- 按路径存取文件
无环图目录
- 无环图目录:在树形目录基础上允许一个文件或子目录拥有多个父目录
- 主要优点是便于文件共享
但这会带来删除问题,因此通常会为共享文件设置共享计数器,只有计数器减到 0 才真正删除文件。
8.4 文件共享
文件共享的核心是:多个用户或多个目录如何共同使用同一份文件,又不把系统搞乱。教材里常见两种实现思路。
利用有向无环图实现文件共享
- 有向无环图:在树形目录基础上,允许同一文件或子目录被多个目录共享,但整体结构中不能出现环
- 不同目录项可以指向同一个索引节点,多个用户共享的其实是同一个文件实体,而不是复制出来的多个副本
- 为了保证删除正确,通常要设置共享计数器;只有计数器减为 0 时,才真正删除文件
利用符号链接实现文件共享
- 符号链接的基本思想是建立一个 Link 类型文件,其中保存目标文件的路径名
- 当用户访问符号链接时,系统先读出路径,再根据路径找到真正目标文件
优点:
- 实现简单
- 便于跨文件系统共享
- 不要求多个目录项必须直接指向同一个索引节点
缺点:
- 访问时要多做一次路径解析,开销更大
- 如果原文件被删除,链接会失效,形成悬空链接
8.5 文件保护
文件共享解决的是“能不能一起用”,文件保护解决的是“谁能怎么用”。也就是说,系统不仅要允许访问,还要限制访问。
保护域
- 访问权:进程对某对象执行某种操作的权利,例如读、写、执行
- 保护域:一组访问权的集合,规定某进程当前能访问哪些对象、能做哪些操作
进程和域的关系有两种:
- 静态联系:进程固定属于某个域,运行期间不变
- 动态联系:进程可在运行过程中切换到其他域
访问矩阵的概念
- 访问矩阵:行表示域,列表示对象,矩阵元素表示“某域对某对象拥有哪些访问权”
- 如果矩阵元素中包含
switch权,则表示进程可从一个域切换到另一个域
访问矩阵这个模型本身很抽象,但它的价值在于把文件保护统一成了一个可以分析和实现的框架。
访问矩阵的修改
- 复制权:允许把某种访问权复制给其他域
- 所有权:对象拥有者可增删该对象的访问权
- 控制权:若某域对另一域具有控制权,可修改对应访问矩阵项
访问矩阵的实现
- 访问控制表 ACL:按列实现。为每个对象建立一张表,记录哪些域对它拥有哪些访问权
- 访问权限表 / 能力表:按行实现。为每个域建立一张表,记录它对哪些对象拥有哪些访问权
这两种实现方式,一个偏“以对象为中心”,一个偏“以主体为中心”。
8.6 文件系统的实现
文件系统真正落地时,操作系统不仅要决定逻辑结构和目录结构,还要把磁盘上的信息与内存中的管理信息组织起来,使“按名存取方便”和“访问效率高”这两个目标同时成立。
实现原则
- 磁盘上的主要信息包括:引导控制块、卷控制块、目录结构、文件 FCB 以及其他文件系统相关信息
- 内存中的主要信息包括:挂载信息表、目录缓存、系统打开文件表、进程打开文件表、文件数据块缓存
可以看出,磁盘上更偏持久化管理,内存中更偏运行时加速。
磁盘分区
- 主分区:可直接建立文件系统,也可用于启动操作系统
- 扩展分区:自身不能直接存放普通数据,主要作用是继续划分出多个逻辑分区
- 逻辑分区:建立在扩展分区中,可像普通分区一样建立文件系统并使用
文件系统挂载
- 文件系统挂载:把一个文件系统接入操作系统目录树,挂到某个挂载点之后,用户才能通过统一路径访问它
挂载时通常需要做几件事:
- 验证设备与文件系统类型是否匹配
- 读取该文件系统的卷控制信息
- 把相关信息加入挂载信息表
挂载完成后,原目录树与新文件系统会连成一个整体;卸载后,该文件系统再从目录树中分离出来。