24文件系统
4.1 文件基本概念
文件:
- 一组具有意义的信息/数据集合
文件属性
创建时间、上次修改时间文件所有者信息
文件名:
- 由创建文件的用户决定文件名,主要是为了方便用户找到文件
- 同一目录下不允许有重名文件
标识符:
- 一个系统内的各文件标识符唯一
- 标识符对用户来说毫无可读性,它只是操作系统用于区分各个文件的一种内部名称
类型:
- 指明文件的类型
- 类型名告知操作系统,用户在打开该文件时所使用的默认软件
位置:
- 文件存放的路径(让用户使用)、在外存中的地址(操作系统使用,对用户不可见)
- 当用户对文件进行打开操作时,操作系统需要将外存中的文件数据读入内存
大小:
- 指明文件大小
保护信息:
- 对文件进行保护的访问控制信息
4.1.1 文件的组织与管理
数据项是文件系统中最基本的数据单位
文件分为以下两种主要逻辑结构:
- 无结构文件:
- 由一些二进制或字符流组成,又称"流式文件"
- 如文本文件
- 有结构文件:
- 由一组相似的记录组成,又称"记录式文件"
- 记录是一组相关数据项的集合
- 如数据库表
- 由一组相似的记录组成,又称"记录式文件"
系统中的各个文件通过一层一层的目录合理有序的组织起来
- 目录:
- 即"文件夹",其实也是一种特殊的有结构文件(由记录组成)
- 用户可以自己创建一层一层的目录,各层目录中存放相应的文件
操作系统提供给文件的基本系统调用功能:
- 创建文件:
- 用户点击新建后,图形化交互进程在背后create系统调用
- 删除文件:
- 用户点击删除后,图形化交互进程通过delete系统调用,将文件数据存外村中删除
- 读文件:
- 用户双击,记事本等应用程序通过read系统调用,将文件从外存读入内存,并显示在屏幕中
- 文件数据存储在外村中,只有将文件数据读入内存后才能让CPu处理
- 写文件:
- 用户通过记事本等应用程序,编辑文件中的内容,点击保存后,记事本等应用程序通过write系统调用,将文件数据从内存写回外存
- 如果不进行保存,修改的内容一直存放在内存中,不会更新到外存中
- 打开文件:
- 用户启动记事本等应用程序后,记事本会执行open系统调用,打开对外村数据的访问通道
- 关闭文件:
- 用户关闭记事本等应用程序后,记事本退出前会执行close系统调用,关闭对外存数据的访问通道
可用几个基本操作完成更复杂的操作,比如:"复制文件":先创建一个新的空文件,再把源文件读入内存,再将内存中的数据写到新文件中
文件在外存的存放方式:
- 与内存一样,外存也是由一个个存储单元组成的
- 每个存储单元可以存储一定量的数据(如1B)
- 每个存储单元对应一个物理地址
- 类似于内存分为一个个"内存块",外存会分为一个个"块/磁盘块/物理块"
- 每个磁盘块的大小是相等的,每块一般包含2的整数幂个地址(如一块包含2\(^{10}\)个地址,即1KB)
- 同样类似的是,文件的逻辑地址也可以分为(逻辑块号,块内地址),操作系统同样需要将逻辑地址转换为外存的物理地址(物理块号,块内地址)的形式
- 块内地址的位数取决于磁盘块的大小
- 操作系统以"块"为单位为文件分配存储空间,因此即使一个文件大小只有10B,但它依然需要占用1KB 的磁盘块
- 外存中的数据读入内存时同样以块为单位,即内存与外存的数据交换单位也是块
文件的物理结构:
- 文件数据可以存放在连续的磁盘块中,也可以离散的存放在几个磁盘块
其他操作系统实现的文件管理功能:
- 文件共享:使多个用户可以共享使用一个文件
- 文件保护:如何保证不同的用户对文件有不同的操作权限
4.2 文件的逻辑结构
文件逻辑结构:
- 在用户看来,文件内部的数据应该是如何组织起来的
文件物理结构: - 在操作系统看来,文件的数据是如何存放在外存中的
类比数据结构的逻辑结构和物理结构,文件操作的具体实现与逻辑结构、物理结构都有关
4.2.1 无结构文件:
- 文件内部的数据就是一系列二进制流或字符流组成,又称"流式文件"
- 如:Windows 操作系统中的.txt 文件
文件内部的数据其实就是一系列字符流,没有明显的结构特性,因此也不用探讨无结构文件的"逻辑结构"问题
4.2.2 有结构文件:
由一组相似的记录组成,又称"记录式文件"。每条记录又若干个数据项组成
- 一般来说,每条记录有一个数据项可作为关键字(作为识别不同记录的ID)
根据各条记录的长度(占用的存储空间)是否相等,可分为以下两类:
- 定长记录:
- 每条记录的长度均相同,各数据项都处于记录中的相同位置,具有相同的顺寻和长度
- 可变长记录:
- 由于数据项的长度不确定,导致每条记录的长度也不确定,甚至有些数据项在某些记录中不存在
根据有结构文件中的各条记录在逻辑上如何组织,可以分为以下三类:
顺序文件:
- 文件件中的记录一个接一个地顺序排列(逻辑上),记录可以是定长的或可变长的。各个记录在物理上可以顺序存储或链式存储
- 顺序存储:
- 逻辑上相邻的记录,物理上也相邻(类似顺序表)
- 链式存储:
- 逻辑上相邻的记录物理上不一定相邻(类似于链表)
- 按照记录的顺序是否与关键词相关,可分为:
- 串结构:记录顺序与关键词无关
- 通常按照记录存入的时间决定记录的顺序,但时间不一定作为主键
- 顺序结构:记录按照关键词顺序排序
- 串结构:记录顺序与关键词无关
关于顺序结构是否能够进行随机存取
| 逻辑结构 | 是否可随机存取 |
|---|---|
| 链式存储 | 不论是定长/克定昌记录,都无法实现随机存取 每次只能从第一个记录开始依次往后查找 |
| 顺序可变长记录存储 | 无法实现随机存取,每次只能从第一个记录开始依次往后查找 |
| 顺序定长记录存储 | 可实现随机存取,假设记录长度为L,则第i个记录存放的相对位置是i*L 1)若采用传结构,则无法快速找到某关键字对应的记录 2)若采用顺序结构,可以快速找到某关键字对应的记录(如折半查找) |
- 显然,只有定长记录的顺序文件可以实现随机存取
- 一般考试题目中提到的顺序文件指的是物理上顺序存储的顺序文件
- 顺序文件的缺点便是增加/删除一个记录比较困难(串结构不考虑记录内关键词的顺序,直接增加/删除相对容易些)
操作系统一般会将在主存中的增删改操作保存在专门的日志中,每隔一定时间将这些日志操作的最终结果同步到外存中,以此减少I/O次数
索引文件:
- 在顺序文件基础上,建立一张索引表以加快文件检索速度,每条记录对应一个索引项
- 索引表本身是定长记录的顺序文件,因此可以快速找到第i 个记录对应的索引项
- 可将关键字作为索引号内容,若按关键字顺序排列,则还可以支持按照关键字折半查找
- 每当增加/删除一个记录时,需要对索引表进行修改
- 由于索引文件有很快的检索速度,主要用于对信息处理的及时性要求比较高的场合
- 可用不同的数据项建立多个索引表
- 如:学生信息表中,可用关键字"学号"建立一张索引表。也可用"姓名"建立一张索引表。这样就可以根据"姓名"快速地检索文件了
- SQL 就支持根据某个数据项建立索引的功能
索引顺序文件:
- 索引顺序文件是索引文件和顺序文件思想的结合。索引顺序文件中,同样会为文件建立一张索引表
- 但该索引表并不是每个记录对应一个索引表项,而是一组记录对应一个索引表项
- 索引顺序文件的索引项也不需要按关键字顺序排列,这样可以极大地方便新表项的插入
假设一个非定长、顺序结构的顺序文件有10000个记录
- 采用关键字检索:
- 只能顺序查找,平均查找5000次
- 采用索引顺序文件结构:
- 可将10000个记录分为100组,每组100个记录
- 顺序查找索引表找到分组,平均查找50个组
- 在找到的分组顺序查找记录,平均查找50个记录
- 采用索引顺序结构,平均共计查找100次
- 建立一个索引表相比关键字检索可以减少大量的查找次数,但是对于数量较多的记录,单级索引顺序表,查找次数依旧较多
为了进一步提高检索效率,可以为顺序文件建立多级索引表
- 要为N 个记录的文件建立K 级索引,则最优的分组是每组N\(^{1/(K+1)}\) 个记录
- 检索一个记录的平均查找次数是$\frac{N^{1/(K+1)}}{2} * $(K+1)
4.3 文件目录
使用文件目录结构,可以让文件之间的组织结构清晰,易于用户查找
- 编程时也可以很方便的用文件路径找到一个文件
- 如:FILE *fp;fp=fopen("F:\data\myfile.dat");用户可以轻松实现"按名存取"
- 目录本身就是一种有结构文件,由一条条记录组成。每条记录对应一个在该放在该目录下的文件
- 目录文件中的一条记录就是一个"文件控制块(FCB)"
文件控制块FCB:
- FCB 的有序集合称为"文件目录",一个FCB就是一个文件目录项
- FCB 中包含了文件的基本信息(文件名、物理地址、逻辑结构、物理结构等),存取控制信息(是否可读/可写、禁止访问的用户名单等),使用信息(如文件的建立时间、修改时间等)
- 最重要,最基本的文件信息还是文件名、文件存放的物理地址
- FCB 实现了文件名和文件之间的映射,使用户(用户程序)可以实现"按名存取"
对目录可进行的操作包括以下几类:
- 搜索:
- 当用户要使用一个文件时,系统要根据文件名搜索目录,找到该文件对应的目录项
- 创建文件:
- 创建一个新文件时,需要在其所属的目录中增加一个目录项
- 删除文件:
- 当删除一个文件时,需要在目录中删除相应的目录项
- 显示目录:
- 用户可以请求显示目录的内容,如显示该目录中的所有文件及相应属性
- 修改目录:
- 某些文件属性保存在目录中,因此这些属性变化时需要修改相应的目录项(如:文件重命名)
目录结构分为以下几类:
-
单级目录结构:
- 早期操作系统并不支持多级目录,整个系统中只建立一张目录表,每个文件占一个目录项(整个系统只有一张目录表)
- 单级目录实现了"按名存取",但是不允许文件重名
- 在创建一个文件时,需要先检查目录表中有没有重名文件,确定不重名后才能允许建立文件,并将新文件对应的目录项插入目录表中
- 单级目录结构不适用于多用户操作系统
-
两级目录结构:
- 早期的多用户操作系统,采用两级目录结构。分为主文件目MFD,Master File Directory和用户文件目录UFD,User Flie Directory
- 主文件目录:记录用户名及相应用户文件目录的存放位置
- 用户文件目录:
- 由该用户的文件FCB组成
- 用户文件目录允许不同用户的文件重名。文件名虽然相同,但是对应的其实是不同的文件
- 两级目录结构允许不同用户的文件重名,也可以在目录上实现实现访问限制(检查此时登录的用户名是否匹配)
- 两级目录结构依然缺乏灵活性,用户不能对自己的文件进行分类
-
多级目录结构:(树形目录结构)
- 用户(或用户进程)要访问某个文件时要用文件路径名标识文件,文件路径名是个字符串。各级目录之间用"/"隔开。从根目录出发的路径称为绝对路径
- 例如,自拍.jpg 的绝对路径是 "/照片/2015-08/自拍.jpg"
- 系统根据绝对路径一层一层地找到下一级目录。刚开始从外存读入根目录的目录表;
- 找到"照片"目录的存放位置后,从外存读入对应的目录表;
- 再找到"2015-08"目录的存放位置,再从外存读入对应目录表;
- 最后才找到文件"自拍.jpg"的存放位置
- 整个过程需要3次读磁盘I/O操作
- 假如每次都从根目录开始查找,是很低效的。因此可以设置一个"当前目录"
- 例如,此时已经打开了"照片"的目录文件,也就是说,这张目录表已调入内存,那么可以把它设置为"当前目录"。当用户想要访问某个文件时,可以使用从当前目录出发的"相对路径"。
- 在 Linux 中,"."表示当前目录,因此如果"照片"是当前目录,则"自拍.jpg"的相对路径为:"./2015-08/自拍.jpg"
- 从当前路径出发,只需要查询内存中的"照片"目录表,即可知道"2015-08"目录表的存放位置,从外存调入该目录,即可知道"自拍.jpg"存放的位置了
- 引入"当前目录"和"相对路径"后,磁盘I/O的次数减少了。这就提升了访问文件的效率
- 树形目录结构可以很方便地对文件进行分类,层次结构清晰,也能够更有效地进行文件的管理和保护
- 但是,树形结构不便于实现文件的共享
-
无环图目录结构:
- 在树形目录结构的基础上,增加一些指向同一节点的有向边,使整个目录成为一个有向无环图。可以更方便地实现多个用户间的文件共享
- 可以用不同的文件名指向同一个文件,甚至可以指向同一个目录(共享同一目录下的所有内容)
- 需要为每个共享结点设置一个共享计数器,用于记录此时有多少个地方在共享该结点。用户提出删除结点的请求时,只是删除该用户的FCB、并使共享计数器减1,并不会直接删除共享结点
- 新建文件是,共享计数器初值为1。只有共享计数器减为0时,才删除结点
- 共享文件不同于复制文件
- 在共享文件中,由于各用户指向的是同一个文件,因此只要其中一个用户修改了文件数据,那么所有用户都可以看到文件数据的变化
索引节点:对FCB的改进
- 在查找各级目录的过程中只需要用到"文件名"这个信息,只有文件名匹配时,才需要读出文件的其他信息。因此可以考虑让目录表"瘦身"来提升效率
- 索引节点包含除了文件名以外的所有信息,每个文件对应一个索引节点,索引表只保留"文件名"以及"索引节点指针"两项数据
- 假设一个FCB是64B,磁盘块的大小为1KB,则每个盘块中只能存放16个FCB
- 若一个文件目录中共有640个目录项,则共需要占用 640/16 = 40 个盘块
- 因此按照某文件名检索该目录,平均需要查询320 个目录项,平均需要启动磁盘20次(每次磁盘I/O读入一块)
- 若使用索引节点机制,文件名占用14B,索引结点指针占2B,则每个盘块可存放64个目录项
- 那么按文件名检索目录平均只需要读入 320/64 = 5 个磁盘块,这将大大提升文件检索速度
- 由于目录项长度减小,每个磁盘块可以存放更多的目录项,检索文件对磁盘的I/O次数减少了很多
- 当找到文件名对应的目录项时,才需要将索引结点调入内存,索引结点中记录了文件的各种信息,包括文件在外存中的存放位置,根据"存放位置"即可找到文件
- 存放在外存中的索引结点称为"磁盘索引结点";当索引结点放入内存后称为"内存索引结点"
- 相比之下内存索引结点中需要增加一些信息
- 比如:文件是否被修改、此时有几个进程正在访问该文件等
4.4 文件的物理结构
文件的物理结构:
- 即文件分配方式,表明文件数据存放在外村的方式
- 磁盘中的存储单元也会被分为一个个"块/磁盘块/物理块"
- 很多操作系统中,磁盘块的大小与内存块、页面的大小相同
- 内存与磁盘之间的数据交换(即读/写操作、磁盘I/O)都是以"块"为单位进行的。即每次读入一块,或每次写出一块
- 在外存管理中,为了方便对文件数据的管理,文件的逻辑地址空间也被分为了一个一个的文件"块"
- 故文件的逻辑地址也可以表示为(逻辑块号,块内地址)的形式
- 用户通过逻辑地址来操作自己的文件,操作系统要负责实现从逻辑地址到物理地址的映射
4.4.1 文件分配方式类型
连续分配:
- 要求每个文件在磁盘上占有一组连续的块
- 物理块号= 起始块号+ 逻辑块号
- 优点:
- 连续分配支持顺序访问和直接访问(即随机访问)
- 文件目录中记录存放的起始块号和长度(总共占用几个块),可以直接算出逻辑块号对应的物理块号
- 连续分配支持顺序访问和直接访问(即随机访问)
- 缺点:
- 连续分配的文件在顺序读/写时速度最快
- 读取某个磁盘块时,需要移动磁头
- 访问的两个磁盘块相隔越远,移动磁头所需时间就越长
- 物理上采用连续分配的文件不方便拓展
- 由于文件连续占用磁盘块,如果文件与文件紧挨着放置,当文件大小扩大时,必须要申请更大的连续空间,将原数据复制到新空间,造成读写效率大幅下降
- 物理上采用连续分配,存储空间利用率低,会产生难以利用的磁盘碎片
- 由于上面不方便扩展的原因,势必会导致空间较小的空间被空闲出来,造成磁盘碎片
- 连续分配的文件在顺序读/写时速度最快
链接分配:
- 采取离散分配的方式,可以为文件分配离散的磁盘块
- 隐式链接:
- 目录中记录了文件存放的起始块号和结束块号
- 也可以增加一个字段来表示文件的长度
- 除了文件的最后一个磁盘块之外,每个磁盘块中都会保存指向下一个盘块的指针,这些指针对用户是透明的
- 优点:
- 很方便文件拓展,不会有碎片问题,外存利用率高
- 若此时要拓展文件,则可以随便找一个空闲磁盘块,挂到文件的磁盘块链尾,并修改文件的FCB
- 很方便文件拓展,不会有碎片问题,外存利用率高
- 缺点:
- 只支持顺序访问,不支持随机访问,查找效率低
- 假设访问的逻辑块号i,从FCB中找到起始块号,即0号块,将0号逻辑块读入内存,获得1号块的物理块号,继续将1号块读入内存,找到2好块的物理块号,依次类推
- 直到读入i号逻辑块,总需要i+1次磁盘I/O
- 指向下一个盘块的指针也需要额外耗费少量的存储空间
- 只支持顺序访问,不支持随机访问,查找效率低
- 目录中记录了文件存放的起始块号和结束块号
考试题目中遇到未指明隐式/显式的"链接分配",默认指的是隐式链接的链接分配
- 显式链接:
- 把用于链接文件各物理块的指针显式地存放在一张表中,即文件分配表FAT,File Allocation Table
- 故目录中只需记录文件的起始块号
- 一个磁盘仅设置一张FAT
- 开机时,将FAT读入内存,并常驻内存
- FAT 的各个表项在物理上连续存储,且每一个表项长度相同,因此"物理块号"字段可以是隐含的
- 优点:
- 很方便文件拓展,不会有碎片问题,外存利用率高,并且支持随机访问
- 当访问逻辑块号i时,从FCB中找到起始块号,若i为合法编号,则查询主存中文件分配表FAT,往后找到i号逻辑块对应的物理块
- 检索FAT不需要读磁盘,只需访问主存
- 相比于隐式链接来说,地址转换时不需要访问磁盘,因此文件的访问效率更高
- 很方便文件拓展,不会有碎片问题,外存利用率高,并且支持随机访问
- 缺点:
- 文件分配表FAT的需要占用一定的存储空间
- 把用于链接文件各物理块的指针显式地存放在一张表中,即文件分配表FAT,File Allocation Table
索引分配:
- 索引分配允许文件离散地分配在各个磁盘块中,系统会为每个文件建立一张索引表,索引表中记录了文件的各个逻辑块对应的物理块
- 索引表的功能类似于内存管理中的页表,建立逻辑页面到物理页之间的映射关系
- 索引表存放的磁盘块称为索引块;文件数据存放的磁盘块称为数据块
- 目录中需要记录文件的索引块是几号磁盘块
- 假设某个新创建的文件"aaa"的数据依次存放在磁盘块2 -> 5 -> 13 -> 9。7号磁盘块作为"aaa"的索引块,索引块中保存了索引表的内容
- 在显式链接的链式分配方式中,文件分配表FAT 是一个磁盘对应一张
- 而索引分配方式中,索引表是一个文件对应一张
- 优点:
- 可以支持随机访问
- 放访问逻辑块号i时,从FCB中找到起始块号,从目录项中得到索引表存放的物理块号,将索引表从外村中读入内存,检索索引表即可对i号块进行直接访问
- 文件拓展也很容易实现
- 只需要给文件分配一个空闲块作为索引表,并在索引表增加一个索引表项即可
- 可以支持随机访问
- 缺点:
- 索引表需要占用一定储存空间
若每个磁盘块1KB,一个索引表项4B,则一个磁盘块只能存放256 个索引项,如果一个文件的大小超过了256块,那么一个磁盘块是装不下文件的整张索引表的
可采用以下方案解决上述问题:
-
链接方案:
- 如果索引表太大,一个索引块装不下,那么可以将多个索引块链接起来存放
- 假设磁盘块大小为1KB,一个索引表项占4B,则一个磁盘块只能存放256个索引项
- 若一个文件大小为256*256KB =65,536 KB = 64MB
- 该文件共有256*256 个块,也就对应256*256个索引项,也就需要256 个索引块来存储,这些索引块用链接方案连起来
- 若想要访问文件的最后一个逻辑块,就必须找到最后一个索引块(第256个索引块),而各个索引块之间是用指针链接起来的,因此必须先顺序地读入前255 个索引块
- 缺点:
- 若文件很大,索引表很长,就需要将很多个索引块链接起来。想要找到i 号索引块,必须先依次读入0~i-1号索引块,这就导致磁盘I/O次数过多,查找效率低下
-
多层索引:
- 建立多层索引(原理类似于多级页表),使第一层索引块指向第二层的索引块
- 也可根据文件大小的要求再建立第三层、第四层索引块
- 假设磁盘块大小为1KB,一个索引表项占4B,则一个磁盘块只能存放256 个索引项
- 若某文件采用两层索引,则该文件的最大长度可以到2562561KB = 65,536 KB = 64MB
- 根据逻辑块号算出应该在索引表的哪个表项,如访问1026号逻辑块,则1026/256=4,1026%256=2
- 因此在一级索引表调入内存,查询4号表项(0号为第一个索引表),将其对应的二级索引表调入内存,再查询二级索引表的2号表项可得到1026号逻辑块存放在的磁盘块号
- 综上所述,访问目标数据块,需要3次磁盘I/O
- 如果采用三层索引,则文件的最大长度为256256256*1KB=16GB,访问目标数据块,需要4次磁盘I/O
- 采用k层索引结构,且顶级索引表为调入内存,则访问一个数据块只需要k+1次读磁盘操作
- 若采用多层索引,则各层索引表大小不饿能超过一个磁盘块
- 缺点:
- 即使是小文件,访问一个数据块依然需要K+1次读磁盘
- 建立多层索引(原理类似于多级页表),使第一层索引块指向第二层的索引块
-
混合索引:
- 多种索引分配方式的结合
- 例如,一个文件的顶级索引表中,既包含直接地址索引(直接指向数据块),又包含一级间接索引(指向单层索引表)、还包含两级间接索引(指向两层索引表)
- 优点:
- 对于小文件来说,访问一个数据块所需的读磁盘次数更少
- 0~7号逻辑块采用直接地址,加上索引表的读入需要读两次磁盘;8~263采用一级索引,加上索引表的读入需要读三次磁盘;264~65799采用二级索引,加上索引表的读入需要读四次磁盘
- 一般计算机中小文件更多,只需要读两次磁盘,因此混合索引可以加快索引速度
- 对于小文件来说,访问一个数据块所需的读磁盘次数更少
- 多种索引分配方式的结合
索引分配注意点:
- 计算出文件的最大长度需要结合多层索引、混合索引的结构
- 各级索引表最大不能超过一个块
- 计算访问某个数据块所需要的读磁盘次数,注意题目信息
- FCB中会存有指向顶级索引块的指针,因此可以根据FCB读入顶级索引块
- 每次读入下一级的索引块都需要一次读磁盘操作
- 注意题目中,顶级索引块是否已调入内存
各分配方式对比汇总
| 分配方式 | 分配描述 | 目录项内容 | 优点 | 缺点 |
|---|---|---|---|---|
| 顺序分配 | 为文件分配的必须是连续的磁盘块 | 起始块号、文件长度 | 顺序存取速度快,支持随机访问 | 会产生碎片,不利于文件拓展 |
| 隐式链接 | 除文件的最后一个盘块之外,每个盘块中都存有指向下一个盘块的指针 | 起始块号、结束块号 | 可解决碎片问题,外存利用率高,文件拓展实现方便 | 只能顺序访问,不能随机访问 |
| 显式链接 | 建立一张文件分配表(FAT),显式记录盘块的先后关系(开机后FAT常驻内存) | 起始块号 | 除了拥有隐式链接的优点之外,还可通过查询内存中的FAT实现随机访问 | FAT需要占用一定的存储空间 |
| 索引分配 | 为文件数据块建立索引表。若文件太大,可采用链接方案、多层索引、混合索引 | 链接方案记录的是第一个索引块的块号,多层/混合索引记录的是顶级索引块的块号 | 支持随机访问,易于实现文件的拓展 | 索引表需占用一定的存储空间。访问数据块前需要先读入索引块。若采用链接方案,查找索引块时可能需要很多次读磁盘操作 |
关于支持随机访问:
- 文件的某种逻辑结构支持随机存取/随机访问"是指:采用这种逻辑结构的文件,可以根据记录号直接算出该记录对应的逻辑地址(逻辑块号,块内地址)
- 假设这个文件的逻辑结构是"顺序文件",并且是定长记录,每个记录长度16B
- 每块大小为1KB,定长记录长度为16B,因此一块有1KB/16B = 64 个记录
- 逻辑块号m = i / 64,块内地址n = (i % 64) * 16,则i 号记录的逻辑地址= (m, n)
- 因此,定长记录的顺序文件可以直接算出i 号记录对应的逻辑地址,即支持随机访问
4.5 文件的逻辑结构与物理结构
使用C语言创建一个无结构文件,保证文件为串行数据
FILE *fp = fopne("test.txt","w"); //打开文件
if( fp == NULL){
printf("打开文件失败!");
exit(0);
}
//写入1w个Hello world
for(int i=0;i<10000;i++)
fputs("Hello world!",fp);
fclose(fp); //关闭文件
该test.txt文件,从用户视角看,即逻辑结构上,每个字符占1B,整个文件占用一片连续的逻辑地址空间
- 假设查找该文件的第16个字符(编号从0开始)
- 用户通过逻辑地址去访问文件,对文件内各个数据的存放物理位置不关心
FILE *fp = fopne("test.txt","r"); //以读方式打开文件
if( fp == NULL){
printf("打开文件失败!");
exit(0);
}
fseek(fp,16,SEEK_SET); //读写指针指向16
char c = fgetc(fp); //从读写指针所知位置读出一个字符
printf("字符:%c",c); //打印从文件读出的字符
fclose(fp); //关闭文件
该test.txt文件,从操作系统视角看,即物理结构上,该文件就是一堆二进制数据,每个磁盘块可存储1KB数据,每个字符占1B,拆分成多个磁盘块存储即可
- 尽管文件被拆分成多个磁盘块,但逻辑块号是相邻的
- 用户只需要指明逻辑地址即可访问该文件中的数据
- 使用 C语言库函数 fseek,将文件读写指针指向位置 n;使用 C语言库函数 fgetc,从读写指针所指位置读出 1B 内容
- fgetc 底层使用了 Read 系统调用,操作系统将(逻辑块号,块内偏移量)转换为(物理块号,块内偏移量)
- 对于连续分配方式,逻辑上相邻的块,物理上也相邻
- 对于链接分配方式,逻辑上相邻的块,物理上通过链接指针表示先后关系
- 对于索引分配方式,操作系统为每个文件维护一张索引表,其中记录了逻辑块号 -> 物理块号 的映射关系
用C语言创建有结构的顺序文件
typedef struct{
int number;
char name[30];
char major[30];
} Student_info;
//以写方式打开文件
FILE *fp = fopne("test.txt","w");
if( fp == NULL){
printf("打开文件失败!");
exit(0);
}
Student_info student[N]; //用数组保存N个学生信息
for(int i=0;i<N;i++){ //生成N个学生信息
student[i].number=i;
student[i].name[0]='?';
student[i].major[0]='?';
}
//将N个学生的信息写入文件
fwrite(student,sizeof(Student_info),N,fp);
fclose(fp);
//以读方式打开文件
FILE *fp = fopne("test.txt","r");
if( fp == NULL){
printf("打开文件失败!");
exit(0);
}
//文件读写指针指向编号为5的学生记录
fseek(fp,5*sizeof(Student_inf),SEEK_SET);
Student_inf stu;
//从文件读出1条记录,记录大小为sizeof(Student_inf)
fread(&stu,sizeof(Student_inf),1,fp);
printf("学生编号:%d\n",stu.numer);
fclose(fp);
该test.txt文件,从操作系统视角看,即物理结构上,和无结构文件一样,就是一堆二进制数据,使用若干个磁盘块分开存储
- 从用户视角看,即逻辑结构上,每个学生记录占64B,通过逻辑地址进行访问
- 对于顺序文件的顺序存储与链式存储
//顺序存储
typedef struct{
int number;
char name[30];
char major[30];
} Student_info;
//链式存储
typedef struct{
int number;
char name[30];
char major[30];
int next; //下一个学生记录的存放位置
} Student_info;
- 顺序存储:各条记录物理上相邻存放,支持随机访问:指可以直接确定第i条记录的逻辑地址

- 链式存储:各条记录离散着存放,用指针表示先后关系

索引文件:
- 从用户视角来看,整个文件依然是连续存放的;在操作系统看来,索引表存放在独立的磁盘块中,其他数据离散存放在磁盘中,索引表完成逻辑地址与物理地址的映射
- 如:前1MB存放索引项,后续部分存放记录

typedef struct{
int number; //学号
int addr; //学生记录的逻辑地址
}IndexTable;
typedef struct {
char name[30]; //姓名
char major[30]; //专业
//还可以添加其他各种学生信息
}Student_info;
4.6 文件的存储空间管理
存储空间的划分:
- 将物理磁盘划分为一个个文件卷(逻辑卷、逻辑盘)
存储空间的初始化:
- 将各个文件卷划分为目录区、文件区
- 文件区:用于存放文件数据
- 目录区:主要存放文件目录信息FCB、用于磁盘存储空间管理的信息
有的系统支持超大型文件,可支持由多个物理磁盘组成的一个文件卷
4.6.1 文件管理方法
空闲表法:
- 分配方式:
- 与内存管理中的动态分区分配很类似,为一个文件分配连续的存储空间
- 空间表项为首个空闲盘块号以及空闲盘块数
- 可采用首次适应、最佳适应、最坏适应等算法来决定要为文件分配哪个区间
- 与内存管理中的动态分区分配很类似,为一个文件分配连续的存储空间
- 磁盘块回收:
- 内存管理中的动态分区分配很类似,当回收某个存储区时需要有四种情况
- 回收区的前后都没有相邻空闲区
- 回收区的前后都是空闲区
- 回收区前面是空闲区
- 收区后面是空闲区
- 回收磁盘块时需要注意表项的合并问题
- 内存管理中的动态分区分配很类似,当回收某个存储区时需要有四种情况
- 空闲表法适用于连续分配方式
空闲链表法:
-
操作系统会保存链头和链尾指针,将所有盘块串联成一条链表
-
空闲盘块链:
- 以盘块为单位组成一条空闲链
- 空闲盘块中存储着下一个空闲盘块的指针
- 分配方式:
- 若某文件申请 K 个盘块,则从链头开始依次摘下 K 个盘块分配,并修改空闲链的链头指针
- 磁盘块回收:
- 回收的盘块依次挂到链尾,并修改空闲链的链尾指针
- 空闲盘块链适用于离散分配的物理结构,但为文件分配多个盘块时可能要重复多次操作
- 以盘块为单位组成一条空闲链
-
空闲盘区链:
- 连续的空闲盘块组成一个空闲盘区,并以盘区为单位组成一条空闲链
- 空闲盘区中的第一个盘块内记录了盘区的长度、下一个盘区的指针
- 分配方式:
- 某文件申请 K 个盘块,则可以采用首次适应、最佳适应等算法,从链头开始检索,按照算法规则找到一个大小符合要求的空闲盘区,分配给文件
- 若没有合适的连续空闲块,也可以将不同盘区的盘块同时分配给一个文件,注意分配后可能要修改相应的链指针、盘区大小等数据
- 磁盘块回收:
- 若回收区和某个空闲盘区相邻,则需要将回收区合并到空闲盘区中
- 若回收区没有和任何空闲区相邻,将回收区作为单独的一个空闲盘区挂到链尾
- 空闲盘区链对于离散分配、连续分配的方式均适用,为一个文件分配多个盘块时效率更高
- 连续的空闲盘块组成一个空闲盘区,并以盘区为单位组成一条空闲链
位示图法:
- 位示图:
- 每个二进制位对应一个盘块
- 如,0"代表盘块空闲,"1"代表盘块已分配
- 一般用连续的"字"来表示
- 如,一个字的字长为16bit,字中的每一位对应一个盘块
- 可以用(字号,位号)对应一个盘块号,也可描述为(行号,列号)
- (字号,位号)=(i,j) 的二进制位对应的 盘块号 b = ni + j;b号块对应的字号 i = b/n,位号 j = b%n
- 每个二进制位对应一个盘块
注意题目中的盘块号、字号、位号从0开始还是1开始
- 分配方式:
- 若文件需要K个块,顺序扫描位示图,找到K个相邻或不相邻的"0"
- 根据字号、位号算出对应的盘块号,将相应盘块分配给文件
- 将相应位设置为"1"
- 磁盘块回收:
- 根据回收的盘块号计算出对应的字号、位号
- 将相应二进制位设为"0"
- 位示图法对于连续分配、离散分配都适用
成组链接法:
- 空闲表法、空闲链表法不适用于大型文件系统,因为空闲表或空闲链表可能过大。UNIX系统中采用了成组链接法对磁盘空闲块进行管理
- 文件卷的目录区中专门用一个磁盘块作为"超级块",当系统启动时需要将超级块读入内存,并且要保证内存与外存中的"超级块"数据一致
- 因此目录块中的读取速度要求快一些

-
每个超级块包含下一组空闲盘块数以及下一组中空闲盘块号清单
- 每个分组的盘块数量是有限制的,且最后一个空闲盘块分组的空闲盘块数一般比其他分组数量要少
- 超级块中空闲块表首项作为下一分组的头,存放再下一组的空闲盘块数以及下一组中空闲盘块号清单
- 依次类推,将所有空闲盘块构成一条分组链表
-
若某空闲盘块后没有下一组空闲盘块时,空闲块表首项块号设置特殊值
-
分配方式:
- 需要分配1个空闲块:
- 检查第一个分组的空闲块数是否足够。假设分组最大盘块数量为100,1<100,因此是足够的
- 分配第一个分组中的1个空闲块,并修改相应数据。从第一个分组中删去被分配的空闲块(表首项最后删除),下一组空闲盘块数-1
- 需要分配100个空闲块:
- 检查第一个分组的块数是否足够。100=100,是足够的
- 分配第一个分组中的100个空闲块
- 但是由于300号块内存放了再下一组的信息,因此300号块的数据需要复制到超级块中
- 超级快直接首项指向下一组400,300块所在分组删去

- 需要分配1个空闲块:
-
磁盘块回收:
- 假设每个分组最多为100个空闲块,此时第一个分组已有99个块,还要再回收一块
- 直接在第一个分组增加回收的盘块号,该分组下一组空闲盘块数+1
- 假设每个分组最多为100个空闲块,此时第一个分组已有100个块,还要再回收一块
- 需要将超级块中的数据复制到新回收的块中,并修改超级块的内容,让新回收的块成为第一个分组
- 则第一个分组,下一组空闲盘块数为1,首项指向新回收的块号

- 假设每个分组最多为100个空闲块,此时第一个分组已有99个块,还要再回收一块
4.7 文件的基本操作
创建文件:Create 系统调用
- 包括以下参数
- 所需的外存空间大小(如:一个盘块,即1KB)
- 文件存放路径("D:/Demo")
- 文件名(这个地方默认为"新建文本文档.txt")
- 进行Create系统调用,执行以下过程:
- 在外存中找到文件所需的空间
如空闲链表法、位示图、成组链接法等管理策略,找到空闲空间
- 根据文件存放路径的信息找到该目录对应的目录文件(此处就是D:/Demo 目录),在目录中创建该文件对应的目录项。目录项中包含了文件名、文件在外存中的存放位置等信息
- 在外存中找到文件所需的空间
删除文件:Delete 系统调用
- 包括以下参数
- 文件存放路径("D:/Demo")
- 文件名("test.txt")
- 进行Delete系统调用,执行以下过程:
- 根据文件存放路径找到相应的目录文件,从目录中找到文件名对应的目录项
- 根据该目录项记录的文件在外存的存放位置、文件大小等信息,回收文件占用的磁盘块
回收磁盘块时,根据空闲表法、空闲链表法、位图法等管理策略的不同,需要做不同的处理
- 从目录表中删除文件对应的目录项
打开文件:Open 系统调用
- 很多操作系统,在对文件进行操作前,要求用户先执行open系统调用
- 包括以下参数
- 文件存放路径("D:/Demo")
- 文件名("test.txt")
- 要对文件的操作类型(如:r 只读;rw 读写等)
- 进行Open系统调用,执行以下过程:
- 根据文件存放路径找到相应的目录文件,从目录中找到文件名对应的的目录项,并检查该用户是否有指定的操作权限
- 将目录项复制到内存中的"打开文件表"中。并将对应表目的编号返回给用户。之后用户使用打开文件表的编号来指明要操作的文件
打开文件时并不会把文件数据直接读入内存。执行系统调用后,会将打开文件表的"索引号"返回给用户,索引号也称"文件描述符"

- 当执行完open系统调用后,原先存储在外存中的目录信息就被复制到执行进程中,即复制到了主存中,后续对文件操作不需要重新查询目录,可以加快文件的访问速度

- 其中打开文件表有两种
- 系统打开文件表:整个系统只有一张,记录所有处于打开的文件清单
- 用户进程的打开文件表:每个进程各有一张,表项系统表索引号指向该文件在系统打开文件表的编号
关闭文件:Close 系统调用
- 该系统调用只需要指明打开文件表中的索引号即可
- 进行Close系统调用,执行以下过程:
- 根据文件存放路径找到相应的目录文件,从目录中找到文件名对应的的目录项,并检查该用户是否有指定的操作权限
- 将目录项复制到内存中的"打开文件表"中。并将对应表目的编号返回给用户。之后用户使用打开文件表的编号来指明要操作的文件
读文件:Read 系统调用
- 包括以下参数:
- 文件索引号
- 要读入多少数据(如:读入1KB)
- 读入的数据要放在内存中的什么位置
- 进行Read 系统调用,执行以下过程:
- 从读指针指向的外存中,将用户指定大小的数据读入用户指定的内存区域中
写文件:Write 系统调用
- 包括以下参数:
- 文件索引号
- 要写出多少数据(如:读入1KB)
- 写回外存的数据放在内存中的什么位置
- 进行Read 系统调用,执行以下过程:
- 从用户指定的内存区域中,将指定大小的数据写回写指针指向的外存
读/写文件"用"文件描述符"即可指明文件,不再需要用到"文件名"
4.8 文件共享
文件共享:
- 操作系统为用户提供文件共享功能,可以让多个用户共享地使用同一个文件
- 多个用户共享同一个文件,意味着系统中只有"一份"文件数据。并且只要某个用户修改了该文件的数据,其他用户也可以看到文件数据的变化
- 如果是多个用户都"复制"了同一个文件,那么系统中会有"好几份"文件数据。其中一个用户修改了自己的那份文件数据,对其他用户的文件数据并没有影响
基于索引结点的共享方式:硬链接
- 由于检索文件时只需用到文件名,因此可以将除了文件名之外的其他信息放到索引结点中
- 索引结点中设置一个链接计数变量count,用于表示链接到本索引结点上的用户目录项数
- 若count = 2,说明此时有两个用户目录项链接到该索引结点上,或者说是有两个用户在共享此文件
- 若某个用户决定"删除"该文件,则只是要把用户目录中与该文件对应的目录项删除,且索引结点的count值减1
- 若count>0,说明还有别的用户要使用该文件,暂时不能把文件数据删除,否则会导致指针悬空
- 文件被创建时,count初值为1;当count = 0 时系统负责删除文件
基于符号链的共享方式:软链接
- 创建一个新的特殊文件,Link类型文件,该文件记录了想要共享的文件的存放路径,类似于windows系统的快捷方式
- Link类型的文件名可以与原始文件不同
- Windows系统中双击打开Link文件时,操作系统判断这个文件是Link类型的"快捷方式"文件,于是会根据其中记录的"路径信息"检索目录,最终找到"QQScLauncher.exe"
- 当用户访问这个特殊文件时,操作系统判断文件属于Link类型文件,会根据其中记录的路径检索查找路径,找到该路径目录表中该文件的表项,从而找到该文件的索引节点

如果Link文件锁链接的文件索引节点被删除了,即记录中的存放路径已经无法到该文件
- 但Link文件并不会发生任何变化,只是通过该文件的路径去查找共享文件会失败
- 软连接方式访问共享文件时,要查询多级目录,会产生多次磁盘I/O,因此软链接访问共享文件速度比硬链接更慢
4.9 文件保护
文件保护是文件系统提供的功能,用于保护文件数的安全,分为以下几种方式:
-
口令保护
- 为文件设置一个"口令"(如:abc112233),用户请求访问该文件时必须提供"口令"
- 口令一般存放在文件对应的 FCB 或索引结点中
- 用户访问文件前需要先输入"口令",操作系统会将用户提供的口令与FCB中存储的口令进行对比
- 如果正确,则允许该用户访问文件
- 优点:
- 保存口令的空间开销不多,验证口令的时间开销也很小
- 缺点:
- 正确的"口令"存放在系统内部,不够安全
-
加密保护
- 使用某个"密码"对文件进行加密,在访问文件时需要提供正确的"密码"才能对文件进行正确的解密
- 一个最简单的加密算法——异或加密,假设用于加密/解密的"密码"为
01001 - 文件的原始数据为
0010 1011 0001 1101 0001 - 加密密码为
0100 1010 0101 0010 1001 - 加密结果为
0110 0001 0100 1111 1000 - 若采用的解密密码为
0100 1010 0101 0010 1001,解密结果则为0010 1011 0001 1101 0001 - 若采用的是不一致的解密密码
0111 1011 1101 1110 1111,则解密结果为0001 1010 1001 0001 0111
- 一个最简单的加密算法——异或加密,假设用于加密/解密的"密码"为
- 优点:
- 密性强,不需要在系统中存储"密码"
- 缺点:
- 编码/译码,或者说加密/解密要花费一定时间
- 使用某个"密码"对文件进行加密,在访问文件时需要提供正确的"密码"才能对文件进行正确的解密
-
访问控制
- 在每个文件的FCB(或索引结点)中增加一个访问控制列表 ACL,Access-Control List,该表中记录了各个用户可以对该文件执行哪些操作
- 访问类型权限
权限类型 权限描述 读 从文件中读数据 写 向文件中写数据 执行 将文件装入内存并执行 添加 将新信息添加到文件结尾部分 删除 删除文件,释放空间 列表清单 列出文件名和文件属性 - 某文件的访问控制列表
用户 读 写 执行 添加 删除 列表清单 father 1 1 1 1 1 1 mother 1 0 1 0 0 1 son 0 0 0 0 0 0 - 有的计算机可能会有很多个用户,因此访问控制列表可能会很大,可以用精简的访问列表解决这个问题
- 精简的访问列表:
- "组"为单位,标记各"组"用户可以对文件执行哪些操作
如:分为 系统管理员、文件主、文件主的伙伴、其他用户 几个分组
- 当某用户想要访问文件时,系统会检查该用户所属的分组是否有相应的访问权限
- 若想要让某个用户能够读取文件,只需要把该用户放入"文件主的伙伴"这个分组即可
- "组"为单位,标记各"组"用户可以对文件执行哪些操作
权限分组 完全控制 执行 修改 读取 写入 系统管理员 1 1 1 1 1 文件所属用户 0 1 1 1 1 文件所属的伙伴 0 1 0 1 0 其他用户 0 0 0 0 0 - 优点:
- 实现灵活、可以实现复杂的文件保护
4.10 文件系统的层次结构
自上而下的文件系统层次结构:

- 用户接口:文件基本操作
- 文件系统需要向上层的用户提供一些简单易用的功能接口
- 这层就是用于处理用户发出的系统调用请求(Read、Write、Open、Close 等系统调用)
- 文件目录系统:文件目录
- 用户是通过文件路径来访问文件的,因此这一层需要根据用户给出的文件路径找到相应的FCB或索引结点
- 所有和目录、目录项相关的管理工作都在本层完成
- 如:管理活跃的文件目录表、管理打开文件表等
- 存储控制模块:文件保护
- 为了保证文件数据的安全,还需要验证用户是否有访问权限。这一层主要完成了文件保护相关功能
- 逻辑文件系统与文件信息缓冲区:文件逻辑结构
- 用户指明想要访问文件记录号,这一层需要将记录号转换为对应的逻辑地址
- 物理文件系统:文件物理结构
- 这一层需要把上一层提供的文件逻辑地址转换为实际的物理地址
- 辅助分配模块:文件存储空间管理
- 负责文件存储空间的管理,即负责分配和回收存储空间
- 设备管理模块:I/O外部设备管理
- 直接与硬件交互,负责和硬件直接相关的一些管理工作
- 如:分配设备、分配设备缓冲区、磁盘调度、启动设备、释放设备等
实际例子:假设某用户请求删除文件"D:/工作目录/学生信息.xlsx" 的最后100条记录
- 用户接口:
- 用户需要通过操作系统提供的接口发出上述请求
- 文件目录系统:
- 由于用户提供的是文件的存放路径,因此需要操作系统一层一层地查找目录,找到对应的目录项
- 存取控制模块(存取控制验证层):
- 不同的用户对文件有不同的操作权限,因此为了保证安全,需要检查用户是否有访问权限
- 逻辑文件系统与文件信息缓冲区:
- 验证了用户的访问权限之后,需要把用户提供的"记录号"转变为对应的逻辑地址
- 物理文件系统:
- 知道了目标记录对应的逻辑地址后,还需要转换成实际的物理地址
- 设备管理程序模块:
- 要删除这条记录,必定要对磁盘设备发出请求
- 辅助分配模块:
- 删除这些记录后,会有一些盘块空闲,因此要将这些空闲盘块回收
4.11 文件系统布局

原始磁盘空间为一整段连续空间,经过物理格式化以后,划分出各个扇区
-
物理格式化:低级格式化
- 划分扇区,检测坏扇区,并用备用扇区替换坏扇区
用户常用的是高级格式化,即逻辑格式化
物理格式化一般是磁盘出厂前所作的操作,需要使用专业软件进行,且重复的物理格式化可能会减少磁盘寿命。一旦使用低级格式化,会清楚磁盘中的所有数据,即使使用专用恢复软件也无法恢复磁盘数据
- 由于硬盘在格式化划分扇区时,会划分一部分备用扇区,当检测到了坏扇区时用备用扇区进行替换
- 操作系统对于使用坏扇区还是备用扇区是透明的,由磁盘自己完整该功能
磁盘空间换分出扇区后,可进行逻辑格式化,将磁盘进行分区/卷,完成各分区的文件系统初始化
- 逻辑格式化:高级格式化
- 将磁盘进行按分区(分卷Volume)进行二次划分,每个分区可以建立独立的文件系统

- 逻辑格式化后,灰色部分就有实际数据了,白色部分还没有数据
- 逻辑格式化过程其实是包含在操作系统安装的过程中,因此逻辑格式化会顺带在每个分区/卷建立文件系统,即先有操作系统才会有文件系统
- 主引导记录用于电脑开机时,将操作系统引入到主存中的一个独立分区
4.11.1 文件系统在内存中的结构
内存中分为用户区和内核区,磁盘在用户区、内核区存储的信息不相同

- 近期进程范文过的目录文件会缓存在内存的内核区中,这样就不需要每次都从磁盘中读入,以加快目录检索速度
- 内存内核区还会存放系统打开文件表和进程打开文件表,系统打开文件表只有一张,进程打开文件表一个进程对应一张
- 进程打开文件表存储在进程的PCB中
发生open系统调用时,打开文件的过程:

- 以只读方式执行open系统调用,检索M目录下的A文件,CPU在磁盘中找到M目录读入主存的目录缓存中
- 在主存目录缓存中查找A文件的FCB,找到FCB后复制到系统打开文件表,表示文件已被打开,并计数1
- 同时将该FCB复制到执行系统调用的文件进程的进程打开文件表中,设定打开方式为只读,并将系统打开表中该文件的索引号复制到进程打开文件表中
- 在进程打开文件表新建该表项后,意味着文件打开命令执行完成,返回给用户一个文件描述符
- 文件描述符可用于后续read、write等系统调用指明对哪个文件进行操作
- read、write系统调用接收到文件描述符后,会在进程文件打开表中找到相应的文件,再通过系统打开文件表索引找到文件的FCB
- 获得了FCB,就可以获得文件在磁盘中的存储物理位置,从而对文件进行操作
4.12 虚拟文件系统
传统文件系统,一般所使用的文件系统操作规范各不相同
- 程序员在编写应用程序的时候如果考虑适配不同的文件系统,需要编写多套代码去实现系统调用过程,极大增大应用程序开发成本
- 如,UFS文件系统打开文件使用open(a,b)函数;NTFS文件系统打开文件使用fopen(x)函数;FAT文件系统打开文件使用openf(p,q)函数
- 同时不同文件系统的文件数据结构也并不相同,打开文件后,其文件数据在内存中的表示方式也不同
- 如,UFS文件系统的目录项为
文件名 + i节点号;FAT文件系统的目录项为文件名 + 文件类型 + 文件大小 + 起始块号 + 其他字段...
- 如,UFS文件系统的目录项为

虚拟文件VFS,virtual File System:
- 向上层用户进程提供统一标准的系统调用接口,屏蔽底层具体文件系统的实现差异
- VFS要求下层的文件系统必须实现某些规定的函数功能
- 如:open/read/write
- 一个新的文件系统想要在某操作系统上被使用,就必须满足该操作系统VFS的要求
- 每打开一个文件,VFS就在主存中新建一个vnode,用统一的数据结构表示文件,无论该文件存储在哪个文件系统
- vnode,即v节点数据结构中一般包括文件名、文件大小、创建者、文件格式、函数功能指针等字段
- vnode只存在于主存中,而如UFS文件系统中的inode节点信息既会被调入主存,也会在外存中存储
- 打开文件后,VFS会创建vnode,并将文件信息复制到vnode中,vnode的功能指针指向具体文件系统的函数功能
4.12.1 文件系统挂载
文件系统挂载,mouting:
- 即文件系统安装/装载,一般指将文件系统挂载到操作系统中
- 如,电脑插入U盘,就是将U盘的文件系统挂载在当前操作系统中
- 文件系统挂载过程:
- 在VFS中注册新挂载的文件系统
- 内存中的挂载表mount table包含每个文件系统的相关信息,包括文件系统类型、容量大小等
- 新挂载的文件系统,要向VFS提供一个函数地址列表
- 将新文件系统加到挂载点mountpoint,也就是将新文件系统挂载在某个父目录下
- 对于windows系统而言,新挂载的文件系统以独立的盘符形式存在,即独立分卷
- 对于MAC系统,新挂载的文件系统会存放在根目录的Volumes目录中,即/Volumes
- 对于linux,可以使用mount指令,将挂载的文件系统直接覆盖在指定的一个目录上(如/mnt/disk),原操作系统该目录的信息会隐藏,直到该挂载文件系统卸载才会恢复
- 在VFS中注册新挂载的文件系统
本文来自博客园,作者:GK_Jerry,转载请注明原文链接:https://www.cnblogs.com/GKJerry/articles/18399342

浙公网安备 33010602011771号