一、 文件系统的基本结构 (File-System Structure)
文件系统驻留在外部存储(如磁盘)上,为了降低复杂性,系统通常采用分层设计 (Layered File System):应用程序 -> 逻辑文件系统 -> 文件组织模块 -> 基础文件系统 -> I/O 控制 -> 设备 。
- 文件控制块 (FCB, File Control Block):这是文件系统最核心的存储结构,包含了关于文件的一切元数据(如文件权限、所有者、创建时间、大小以及数据块的指针) 。
🎬 内存中的文件操作流程 打开文件
(open):系统在目录结构中查找文件名,提取对应的
FCB,并将其复制到内存中的系统级打开文件表 (system-wide open-file
table) 中 。
- 读取文件
(
read):利用进程级打开文件表中的索引,找到系统级表中的 FCB,进而找到磁盘上的数据块 。
二、 虚拟文件系统 (Virtual File Systems, VFS)
由于世界上存在各种各样的文件系统(本地的 NTFS、Ext4,网络的 NFS 等),操作系统如何统一管理它们?
核心思想:VFS 提供了一种面向对象 (object-oriented) 的方法。它在应用程序和具体的文件系统之间抽象出了一层统一的系统调用接口 (API) 。
用户只需调用标准的
open(),read()等 API,VFS 会自动判断这是一个本地文件还是远程文件,并将其路由到对应的底层文件系统去执行 。
三、 目录的实现 (Directory Implementation)
在底层,目录本质上就是一张“文件名 -> 数据块指针”的映射表。实现方式有两种:
线性列表 (Linear list):最简单的实现,但每次查找文件都需要线性遍历,非常耗时 。
哈希表 (Hash Table):带哈希数据结构的线性列表。
优点:极大地减少了目录的搜索时间 。
缺点:大小固定,且容易发生碰撞 (collisions)(两个不同的文件名算出了相同的哈希值) 。
四、 磁盘空间的分配方法 (Allocation Methods) 🌟【本章绝对核心考点】
文件的数据在磁盘上究竟是怎么存放的?这就像是如何安排旅游团的客人入住酒店的房间。
1. 连续分配 (Contiguous Allocation) —— “包下整层楼”
要求每个文件在磁盘上占用一组连续的物理块 。
优点:极简,只需要记录“起始块号”和“长度”。支持随机访问 (Random access),磁头移动距离极短,速度最快 。
致命缺点:严重的空间浪费(动态存储分配问题,会产生外部碎片);且文件无法轻易扩展大小(因为后面的块可能被别人占了) 。
改良版:基于扩展的系统 (Extent-Based Systems):按“扩展块 (extents)”为单位分配,一个文件可以由多个连续的扩展块组成 。
2. 链接分配 (Linked Allocation) —— “寻宝游戏”
文件是磁盘块的链表,块可以散布在磁盘的任何角落。每个块的末尾包含一个指向下一个块的指针 。
优点:只需要知道起始地址;永远不会有外部碎片,空间利用率高;文件可以无限增长 。
缺点:不支持随机访问(要读第 10 块必须先读前 9 块);指针本身也要占用磁盘空间 。
经典变体:FAT (文件分配表, File-Allocation Table) :MS-DOS 和 OS/2 采用的方案。它将所有块的“指针”抽离出来,集中存放在内存的一张表(FAT)中,这极大地改善了寻道时间 。
3. 索引分配 (Indexed Allocation) —— “建立专属通讯录”
为每个文件分配一个专属的索引块 (index block),里面集中存放了该文件所有数据块的物理地址指针 。
优点:既支持随机访问,又没有外部碎片问题 。
缺点:索引块本身会带来空间开销。如果是极小的文件,单单为了几个指针也要分配一整个索引块 。
大文件如何映射? 如果文件极大,一个索引块装不下指针怎么办?可以使用链接方案 (Linked scheme)(索引块链接索引块)或 多级索引 (Two-level index)(外层索引块指向内层索引页,内层再指向数据块) 。
👑 UNIX 的混合索引分配方案 (Combined Scheme)
UNIX 系统将上述思想融合,其 inode (即 FCB) 结构极其精妙 :
包含约 12 个 直接块指针 (direct blocks):指向数据块。适合绝大多数小文件。
包含 1 个 一级间接指针 (single indirect):指向一个装满指针的块。
包含 1 个 二级间接指针 (double indirect):指向一个装满一级间接指针的块。
包含 1 个 三级间接指针 (triple indirect):用于支持极巨大的文件。
(这种设计完美兼顾了小文件的访问效率和超大文件的扩展性)
五、 空闲空间管理 (Free-Space Management)
磁盘那么大,系统怎么知道哪些块是空闲的?
位图/位向量 (Bit vector / Bit map):用一串
0和1表示。0表示空闲,1表示被占用 。优点:非常容易找到连续的空闲块 。
缺点:位图需要占用额外的内存空间。例如
字节的磁盘,需要 32KB 的位图 。
链表 (Linked list):将所有空闲块用指针链成一个链表 。
优点:不浪费额外空间 。
缺点:很难找到连续的空闲块 。
保护与一致性:空闲空间列表的指针或位图必须保存在磁盘上。内存和磁盘中的拷贝可能会不一致。通常的解决逻辑是:先在磁盘上标记为已分配,然后再在内存中标记 。
六、 效率、性能与恢复 (Performance & Recovery)
缓存加速 (Caching) :
页面缓存 (Page Cache):使用虚拟内存技术缓存页面,支持内存映射 I/O 。
统一缓冲区缓存 (Unified Buffer Cache):现代操作系统使用同一个页面缓存来同时处理“内存映射页面”和“普通的系统调用(read/write) I/O”,避免了数据的双重缓存和浪费 。
预读 (read-ahead) 与 延迟释放 (free-behind):针对顺序访问的优化 。
恢复机制 (Recovery):
- 一致性检查 (Consistency checking):对比目录结构和磁盘数据块尝试修复错误 。
基于日志的文件系统 (Log-Structured / Journaling File Systems):
将对文件系统的所有更新作为事务 (transaction) 记录到日志中 。
事务写入日志即视为提交,稍后会异步写入真正的文件系统。如果系统崩溃,重启时只需重做日志中未完成的事务,极大提高了系统的安全性和恢复速度 。
七、 网络文件系统 (NFS, Network File System)
NFS 是 Sun 公司开发的允许在局域网/广域网上访问远程文件的软件系统 。
挂载与透明性:可以将远程机器的目录挂载 (mounted) 到本地文件系统的某个节点上。一旦挂载完成,用户访问远程文件就和访问本地文件一样透明 。
无状态服务器 (Stateless Server):NFS 服务器不保存客户端的状态。每个请求都必须包含完整的参数信息。修改后的数据必须在结果返回给客户端前写入服务器的磁盘 。
架构层级:当用户发起系统调用时,请求先交给 VFS。VFS 会判断:如果是本地文件,转给本地文件系统;如果是网络文件,转给 NFS 客户端,NFS 客户端再通过 RPC/XDR 协议通过网络发送给 NFS 服务器 。
📝 附录:本章经典考题回顾
题目:下列文件物理结构中,适合随机访问且易于文件扩展的是?
A. 连续结构 B. 索引结构 C. 链式结构且磁盘块定长 D. 链式结构且磁盘块变长
答案:B. 索引结构。
解析:连续结构适合随机访问,但不易扩展(A错);链式结构易于扩展,但不支持随机访问(C、D错);索引分配既通过索引块支持了直接/随机访问,又允许文件在磁盘上分散存储从而易于扩展,完美符合要求 。
如果您喜欢我的文章,可以考虑打赏以支持我继续创作.