文章目录
初识文件管理
- 文件管理包含文件的内部组织和文件的内部组织
- 内部组织:逻辑上的组织and物理上的组织
2.1 文件的逻辑结构一般不考- 外部组织:文件之间通过目录组织起来
- 目录由文件控制块FCB构建起来的
- 一个文件控制块FCB对应一个文件目录项
- 不同用户对文件的操作权限是不同的,所以文件控制块中包含存取控制信息
逻辑结构
根据有结构文件中的各条记录在逻辑上如何组织,可以分为三类
顺序文件
- 定长记录的顺序文件,若物理上采用顺序存储,则无论是采用串结构or顺序结构都行实现随机存取。只不过串结构无法根据关键字快速检索
- 顺序文件有两种结构:串结构(时间)and 顺序结构(关键字)
- 串结构增删一条记录相对简单
- 在对记录进行批量处理处理时,顺序文件的效率是所有逻辑文件中最高的。
- 只有顺序文件才能存储在磁带上
索引文件
- 解决顺序文件增删记录不方便的问题
- 可以让不定长文件实现随机存取
- 索引表用于记录每一个文件所对应的物理地址
- 索引表是一个定长记录的顺序文件,可以实现随机存取
- 如果为每一个文件都建立一个索引项,那么这个索引表可能非常大
- 对于索引文件方式,如果要记录可变长文件的地址,除了要记录起始地址外,还需要记录这个文件的长度
索引顺序文件
- 索引顺序文件就是将索引表中的记录分组, 将每个分组对应一个索引项。
- 查找一条记录时,先通过索引表找到其所在的组,然后在改组中使用顺序查找,就能很快找到记录
- 注意:索引顺序文件中的索引表只包含关键字和指针两个部分
这个与索引文件中的索引表不同
注意k级索引,查找一个文件要查找k+1次
文件目录+文件控制块
- 索引节点就是让目录表瘦身,目录表中只存放文件名和索引节点的地址。
- 索引节点中保存目录表中的其他剩余信息
查找过程中,如果命中了目录表中的目录项,就读取对应的索引节点- 引入索引节点可以提高查找文件的效率
- 当不引入索引节点时
每个磁盘可以存放16个FCB,也就是16个目录项,640个目录项就需要640/16=40块磁盘来存放,对于640条目录项,平均检索一条目录需要查询320个目录项,320个目录项需要320/16=20块磁盘,也就是说,需要启动磁盘20次- 当引人了索引节点
假设一个目录项FCB只占16个字节,那么一个磁盘就可以存放1KB/16=64个目录项,那么在640条目录项中查找目标记录时,平均访问320次,320/64=5块磁盘,也就是说只需要启动5次磁盘。
- 在 Linux 中,“.”表示当前目录
- 在树形目录结构中,根据相对路径检索文件可以减少磁盘IO次数,因为每查询下一级目录的时候都要启动磁盘,然后把下一级文件目录从外存调入内存
- 无环图目录结构
文件共享
硬链接可以联系无环图目录结构(找不到直接搜索关键字)
软连接可以理解为:
1.1 用户B要访问用户A的一个文件F,可以由系统创建一个LINK类型的新文件L,这个新文件L中只保存了文件F的路径地址。
1.2用户B的目录文件中加入这个文件L
1.3 用户要访问F,就找到这个文件L,读取了文件L中的保存的F的地址信息,然后再去找文件F只有文件F的拥有者用户A才拥有指向其索引节点的指针。
注意:建立符号链接时,引用计数值直接复制
文件保护
文件实现-文件分配方式(非空闲)
- OS对空闲磁盘块和非空闲磁盘块都要进行管理
- 文件分配方式or文件的物理结构:是对非空闲磁盘块的探索
- 文件存储空间管理:是对空闲磁盘块的探索
1. 连续分配
连续分配会产生外部碎片
2. 链接分配
2.1 隐式链接
隐式链接:访问一次磁盘,将磁盘中的一个物理块读入内存,读取这块文件后才能知道下一个物理块存放在磁盘的什么位置。
2. 2 显示链接(FAT表)
注意:
- 显式链接支持随机访问!!!隐式链接不支持
- 相比于隐式链接,地址转换时不需要访问磁盘
- FAT是常驻内存的
3. 索引分配(索引表:一个文件一张)
注意索引分配中的索引表与显示链接中的FAT文件分配表区别
- 索引表:一个文件对应一张表
- FAT:一个磁盘对应一张
注意:FAT是常驻内存的,索引表保存在磁盘中
索引分配问题解决(索引表太大)
链接方案(将多个索引表链接)
多层索引(类似于多级页表)
混合索引(inode)
分配方式总结
文件实现-文件存储空间管理(空闲块)
注意FCB存储在磁盘的目录区
1. 空闲表法
2. 空闲链表法
连续的多个空闲盘块组成一个空闲盘区
空闲链表法:OS保存了链头and链尾指针,链头指针在分配空闲块的时候用,链尾指针在回收空闲块的时候用
3. 位示图法
4. 成组链接法(不常考,需要看视频理解)
总结
文件操作
- 打开文件:
在用户打开了一个文件之后,这个文件相关的那些信息就已经放入内存当中了, 之后如果用户想要操作这个文件,只需要根据打开文件表的编号就可以找到这个文件的所有信息,这样就不需要每次查文件的时候都重新访问目录了。因此,把目录项复制到打开文件表当中,是可以大幅度提升文件访问速度的。- 打开文件表分为两种
系统的打开文件表:
- 这个打开文件表中会记录所有的正在被其他进程使用的文件的信息
- 这个表中包含一个打开计数器的字段
- 打开计数器:用于记录有多少个进程打开了该文件。
- 整个系统只有一张
每个进程也有一张自己的打开文件表
- 这个表用于记录这个进程此时打开的文件有哪些
- 进程打开文件表中有一个系统表索引号字段
- 系统表索引号:
磁盘结构(注意簇的概念)
- 通俗的来讲,在Windows下如NTFS等文件系统中叫做簇;在Linux下如Ext4等文件系统中叫做块(block)。每个簇或者块可以包括2、4、8、16、32、64…2的n次方个扇区。
- 簇也可以称作分配单元(allocation unit),它是操作系统磁盘文件存储管理的单位,可为一个或多个物理扇区组成,由格式化时选定的文件系统而定。簇是操作系统所使用的逻辑概念而非磁盘的物理特性。
- 簇是系统在硬盘上读写文件时的单位,是一个数据块。而扇区是硬盘划分的最小单位值,就是簇(数据块)占用的地方。
- 打个比方,你(系统)要在仓库(仓库可视为硬盘)里存放一些书(数据)。你先把书分门别类放到一些大纸箱(簇)里,然后放进仓库,纸箱的体积是根据你仓库大小来决定的,而仓库始终划分成单位为0.1m³的小格子(扇区),仓库大了,纸箱就大些,仓库小了,纸箱就小些。
- 绝大多数操作系统以簇为单位进行空间分配
- 先确定柱面号:磁头移动到指定磁道
- 再确定盘面号:决定激活哪个盘面的磁头
- 磁盘的物理地址编号是按照
1、柱面号->盘面号->扇区号
而不是
2、盘面号->柱面号->扇区号
原因是如果按照2来编号,存取数据的时候首先确定一个盘面,然后磁头需要在盘面的不同柱面间移动,耗费时间较多
而采用1的方式由于顺序编号会按照柱面来编号,故在存取数据时只有当整个柱面的数据都被存取完才需要切换柱面进入下一个柱面,这才需要移动磁头,因此相比2大大减少了磁头移动的距离,缩短了寻道时间。
注:采用1相同柱面不同磁道间存取数据时只需要激活相应盘面的磁头即可,不需要移动磁头。因为磁头由上到下在每个盘面上都有,且是在一条垂直直线上同时运动的。
总的平均存取时间 T a = T S + 1/2r + b/(rN)
磁盘调度算法
减少延迟时间的方法:(交替编号+错位命名)
磁盘的管理(初始化+引导块+坏块)
文件层次结构
目录的操作(新增)
首先create创建一个目录,你在你的Windows电脑上点右键,是不是就可以新建创建一个目录?那这个目录它本身也是一个文件,因此创建这个目录需要在磁盘当中给他分配存储空间,同时当我们创建一个目录的时候,肯定得指明这个目录是被包含的哪一级的父目录下面,对吧?比如我们要创建一个新的目录A,它存放在一个叫作B的目录下面,那么我们创建新目录A的同时,是不是也需要在他的父目录B这个目录的信息里面新增一个目录项FCB用于记录B的下面有一个叫做a的那个文件,这个文件的类型是一个目录,然后同时也需要记录a这个目录文件,她在磁盘当中的存放位置,占了多少个磁盘空间等等
,需要有这样一些信息,所以我们创建一个新目录,除了给他分配磁盘空间以外,还需要在他的父目录当中创建一个指向新目录的一个FCB,这就是是创建根目录。
当我们在创建一个目录的时候,一个新的目录,刚开始这个目录下面是没有任何一个文件的,对吧?所以照理来说,一个新创建的目录,它里边应该不包含任何一个FCB,所有的FCB都是空的,但事实上任何一个目录被创建之后,这个目录当中都会有两个默认存在的FCB,一个名字叫做点,另一个名字叫做点点。使用命令行的同学知道,你有时候会cd点,然后什么什么东西对吧?或者cd点点,然后什么什么东西?那这个点指的就是从当前目录出发去查找下一级的这个目录,而点点指的是从当前目录的父目录出发,上一级目录出发往下。去找其他的文件好,所以任何一个目录被新建之后,都会有两个默认的FCB,两个默认的FCB被填充进去。一个FCB的文件名叫做点,另一个FCB的文件名叫点点,一个点的这个FCB表示的是当前这个目录,所以它指向的就是这个目录文件它本身,而另一个FCB点点,它是指向了父目录文件。所以当我们新建一个目录的时候,刚开始他并不是呃全空的,会有两个默认的FCB存在。
删除一个目录,那删除目录就是创建目录的一个逆操作,我们要回收分配给目录的磁盘空间,同时也需要删除指向这个目录的FCB。需要注意的是:只有空目录才可以。
如果要强行删除一个非空目录的话,那么会导致这个非空目录下面的所有文件也全部一起被删除。
open打开目录的操作和打开普通文件一样,open系统调用只是把指向这个目录文件的FCB读入了内存而已,并不是把这个目录文件实际的数据给读者内存。
而我们要把这个目录文件的数据读入内存,需要用read系统调用,对目录文件的read系统调用,通常每一次read就是读入下一个目录项
。
比如此时我们要读的是a这个目录,而A这个目录里面包含了很多很多个FCB,那对于A这个目录的read系统调用,每调用一次就会给我们返回一个FCB,下一次read就会返回下一个FCB。并不是每次read都会导致读磁盘的操作,比如说a这个目录文件,它本身只有一块磁盘块,那么我们在第一次read将读出a的第一个FCB的时候,我们会把这一块的数据给读入主存,那往后每一次read,只需要从主存当中取出下一个FCB返回给系统调用的调用者就可以了。所以并不是每次read都会导致读磁盘操作。
可以对目录文件的操作叫做rename ,就是重命名,你在你的电脑上经常给你的文件夹给你的目录重命名,对吧?那重命名的本质就是要修改指向这个目录文件的FCB.
link就是要建立硬链接,我们可以指明某一个文件,同时指明某一个目录。然后建立一个硬链接,比如我们有一个文件C,这是原本就存在的一个文件,那我们可以指明我们要在目录a下面建立文件c的硬链接,那这个时候就可以使用link系统调用,那这个系统调用会使得目录文件a当中多一个FCB目录项。这个目录项是指向了C这个文件,这就会导致C这个文件的inode当中,它的共享计数器+1,
unlink系统调用就是解除一个硬链接,如果要解除c文件在a目录下的硬链接,那么使用unlink系统调用就会使得a下面的这个目录项被删除,同时c这个文件它的inode的共享计数器减1。而如果共享计数器为零,那么就说明当前没有任何一个目录项指向这个文件,就可以把这个文件的数据给删除了,那回到刚才这个图,你会看到每一个文件的索引节点当中,都会有一个共享计数器。这个共享计数器表示的就是当前有几个目录项指向了这个文件,也就是目前有几个硬链接。
虚拟文件系统
文件系统挂载(mounting)