文件系统基础
文件是以硬盘为载体的存储在计算机上的信息集合,文件可以是文档、图片、程序等。在系统运行时,计算机以进程为基本单位进行资源的调度和分配;而在用户的输入和输出中,则以文件为基本单位
文件控制块和索引节点
与进程管理类似,操作系统引入了文件控制块的数据结构
1.文件的属性
除了文件数据,操作系统还会保存与文件相关的信息,如所有者、创建时间等,这些附加信息称为文件属性或文件元数据。文件属性在不同系统中差别很大,但通常都包含如下属性:
属性名 | 描述 |
---|---|
名称 | 同目录下文件名唯一 |
类型 | 被支持不同类型的文件系统所使用 |
创建者 | 文件创建者的ID |
所有者 | 文件当前所有者的ID |
位置 | 指向设备和设备上文件的执政 |
大小 | 文件当前的大小,也可包含文件允许的最大值 |
保护 | 对文件保护的访问控制信息 |
创建时间 | 最后一次修改时间和最后一次存取时间 |
2.文件控制块FCB
文件控制块FCB是用来存放控制文件需要的各种信息的数据结构以实现“按名存取”。FCB的有序集合称为文件目录,一个FCB就是一个文件目录项。一个文件目录也被视为一个文件,称为目录文件。
FCB主要包含以下信息:
- 基本信息,如文件名、文件的物理地址、文件的物理结构等
- 存取控制信息,包括文件的存取权限,核准用户的存取以及一般用户的存取权限
- 使用信息,如文件创建时间、上次修改时间等
文件的基本操作
操作系统提供系统调用,对文件的创建、写、读、重定位、删除、截断等操作
- 创建文件。创建文件有两个必要步骤:一是为新文件分配必要的外存空间;二是在目录中为之创建一个目录项
- 写文件。为写文件执行一个系统调用。对于给定文件名,,搜索目录以查找文件位置。系统必须为改文件维护一个写位置的指针。每当写操作发生时,更新写指针
- 读文件。为读文件执行一个系统调用。同样需要搜索目录以找到相关的目录项,系统维护一个读位置指针。每当发生读操作时,更新读指针。
- 重新定位文件,也称文件定位。搜索目录以找到适当的条目,并将当前文件位置指针重新定位到给定值。重定位文件不涉及读、写。
- 删除文件。为了删除文件,先从目录中检索指定文件名的目录项,然后释放该文件所占的存储空间,并删除目录条目
- 截断文件。允许文件所有属性不变,并删除文件内容,将其长度置为0并释放其空间。
什么是系统调用?
系统调用 是内核提供给应用程序使用的功能函数,由于应用程序一般运行在 用户态 ,处于用户态的进程有诸多限制(如不能进行 I/O 操作),所以有些功能必须由内核代劳完成。
文件的打开和关闭
在文件使用之前通过系统调用open被显示打开。操作系统维护一个包含所有打开文件信息的表(打开文件表)。所谓的打开其实是指系统调用open根据文件名搜索目录,将指明文件的属性,从外存复制到内存打开文件表的一个表目中,并将该表目的编号返回给用户。当用户再次请求该文件时,可通过索引在打开文件表中查到文件信息,从而节省搜索目录的开销。当文件不再使用时,可利用系统调用close关闭它,操作系统会从打开文件表中删除这一目录。
在多个进程可同时打开文件的操作系统中,通常采用两级表:整个系统表和每个进程表。通常系统打开文件表为每个文件关联一个打开计数器,以记录多少进程打开了 改文件,当打开计数器为0时,则表示该文件不被使用,可以从系统打开文件表中是
文件的逻辑结构
按逻辑分,文件可划分为无结构文件和有结构文件。
无结构文件
无结构文件:文件内部的数据是一系列二进制或字符流组成。又称为“流式文件”,例如Windows系统中的.txt
文件
有结构文件
有结构文件:由一组相似的记录组成,又称为“记录式文件”。每条记录又由若干个数据项组成。如:数据库表文件,一般来说,每条记录有一个数据项可作为关键字。根据记录的长度(占用的存储空间)是否相等,又可分为定长记录和变长记录两种。
有结构文件的逻辑结构
有结构文件按记录可分如下几种
顺序文件
文件中的记录一个接一个地顺序排列,记录通常是定长的,可以顺序存储或以链表的形式存储(这个是存储形式,区别于后面的串行和顺序结构)。顺序文件有以下两种结构:
- 串结构,记录之间的顺与关键字无关,通常是按存入时间的先后进行排列,对串结构文件进行索引必须从头开始依次查找,比较费时
- 顺序结构,指文件中的所有记录按关键字顺序排列,可以采用折半查找法,提高了检索效率
在每次进行大批读写记录时,顺序文件的效率是所有逻辑文件中最高的,但是在经常要查找修改或删除三个记录的场合,顺序文件的性能也比较差。对于顺序存储设备(如磁带),也只有顺序文件才能被存储并能有效的工作。
索引文件
采用索引文件时,会建立一张索引表,以加快文件检索速度。每条记录对应一个索引项。索引表本身是定长记录的顺序文件,可以将关键字作为索引号的内容,若按关键字顺序排列,则可以支持按照关键字的折半查找。这样就把对变长记录顺序文件的检索转变为对定长记录索引文件的随机检索
索引顺序文件
考虑到索引文件的缺点:每个记录都会对应一个索引表,因此索引表可能会很大。所以可以跟多级段表的思想差不多,索引顺序文件将顺序文件中的所有记录分为若干组,为顺序文件建立一张索引表,在索引表中为每个组的第一条建立一个索引项,其中含有该记录的关键字值执行该记录的指针。
索引顺序文件可以进一步提高查找效率,采用多级索引文件能让查找次数更少
索引文件的索引表一定要保证按关键字有序排列,而索引顺序文件的索引表不一定要有序。因此查询索引顺序文件的索引表时,一般使用顺序查找
文件的物理结构
文件块、磁盘块
在内存管理中,进程的逻辑地址空间被分为一个一个页面
同样的,在外存管理中,为了方便对文件数据的管理,文件的逻辑地址空间也被分为了一个一个的文件“块”,于是文件的逻辑地址也可以表示为(逻辑块号、块内地址)的形式
连续分配
- 连续分配*方式要求每个文件在磁盘上占有一组连续的块。这种排序方式使作业访问磁盘时需要的寻道数和寻道时间最小。
采用连续分配时,文件目录汇总记录存放的起始块号(这片连续区域的开端)和长度。用户给出要访问的逻辑块号,操作系统可以通过 物理块号 = 起始块号 + 逻辑块号 物理块号 = 起始块号+逻辑块号 物理块号=起始块号+逻辑块号来找到在磁盘上的存储。当然还需要检查用户提供的逻辑块号是否合法(逻辑块号>=长度就不合法)
连续分配方式的缺点:①物理上采用连续分配的文件不方便拓展;②为保持文件的有序性,删除和插入记录时,需要对相邻的记录做物理上的移动;③很难确定一个文件需要的空间大小,因而只适用于长度固定的文件;④反复增删文件后会产生外部碎片,存储空间利用率低
链接分配
链接分配采取离散分配的方式,可以为文件分配离散的磁盘块。分为隐式链接和显示链接两种。这两种方式都不会产生外部碎片,同时可以很方便地对文件进行拓展。显示链接和隐式链接最大的不同就是下一块的地址是否透明
隐式链接分配
隐式链接分配的方式如下图所示,目录项中含有文件的第一块指针和最后一块指针。每个文件对应一个磁盘块的链表;磁盘块分布在磁盘的任何地方,除最后一个盘块外,每个盘块都含有指向文件下一个盘块的指针,这些指针对用户透明。
采用**链式分配(隐式链接)**方式的文件,只支持顺序访问,不支持随机访问,查找效率低。另外,指向下一个盘块的指针也需要消耗少量的存储空间,但是很方便文件的拓展,不会有碎片问题,外存利用率高
显示链接
显示连接是指把用于链接文件各个物理块的指针,从每个物理块末尾提取出来,显式地存放在内存的一张连接表中。FAT只在磁盘中设置一张,称为文件分配表FAT(File Allocation Table)。每个表项中存放指针,即下一个盘号。FAT的各个表项在物理上连续存储,且每一个表项的长度相同,因此“物理块号”字段可以隐含。
采用显示链接分配的方式,将逻辑块号转化成物理块号的过程不需要读磁盘操作,同时支持顺序访问,也支持随机访问(可以在表中直接访问某个逻辑块号)。FAT中的下一块
索引分配
索引分配允许文件离散地分配在各个磁盘块中,系统会为每个文件建立一张索引表,索引表中记录了文件的各个逻辑块对应的物理地址(类似于内存管理中的页表,建立逻辑页面到物理页面之间的映射关系)。索引表存放的磁盘块称为索引块。文件数据存放的磁盘块称为数据块。
如下图文件“aaa”的数据依次存放在磁盘块的2->5->13->9。其中7号磁盘块作为"aaa"的索引块,索引块中保存了索引表的内容,索引表中的逻辑块号是可以隐藏的。
注:
- 在显示连接分配方式中,文件分配表FAT是一个磁盘对应一张的,而索引分配方式则是一个文件对应一张索引表。
- FAT的表项中,每一项为逻辑块号和一块逻辑号,而索引表中的项则是一个逻辑块号对应一个物理块号
索引块的大小是一个重要的问题,每个文件必须有一个索引块,因此索引块的大小尽可能小,但索索引表太小就无法支持文件。可以采取以下几个机制来解决这个这个图 问题
链接方案
如果一个索引表太大,一个索引块装不下,可以将多个索引块链接起来存放。
缺点:若文件很大,索引表很长,就需要将很多个索引块链接起来。想要找到i
号索引块,必须先依次读入0~i-1
号索引块,这就导致磁盘IO次数过多,查找效率低下
多层索引
建立多层索引(原理类似于多级页表)。使第一层索引块指向第二层索引块还可以根据文件的大小建立跟多级的索引块。
缺点是即使是小文件,访问一个数据块依然需要k+1
次读磁盘
混合索引
多种索引分配方式的结合。例如,一个文件的顶级索引表中,既包含直接地址索引(直接指向数据块),又包含一级间接索引(指向单层索引表)、还包含两级间接索引(指向两级索引表)
优点:对于小文件来说,访问一个数据块所需的读磁盘次数更少
小结
文件的逻辑结构VS物理结构
文件的逻辑结构是用户可见的,即从用户的视角看到的文件的全貌。文件的物理结构是文件在存储器上的组织结构,它表示一个文件在辅存上的安置、链接、编目的方法。或者可以这么理解:文件的物理结构决定了文件在所拥有的空间在磁盘上是怎么存的,逻辑结构则告诉你文件的这些空间是怎么用的
文件目录
文件控制块
FCB的有序集合称为文件目录,一个FCB就是一个文件目录项。文件管理系统和文件集合相关联的是文件目录,它包含有关文件的属性、位置和所有权等。其中最重要,最基本的还是文件名、文件存放的物理地址
FCB需要对目录进行哪些操作:
- 搜索:当用户要使用一个文件时,系统要根据文件名搜索目录,找到该文件对应的目录项
- 创建文件:创建一个新的文件时,需要在其所属的目录中增加一个目录项
- 删除文件:当删除一个文件时,需要在目录中删除相应的目录项
- 显示目录:用户可以请求显示目录的内容,如果显示该目录中的所有文件及相应属性
- 修改目录:某些文件属性保存在目录中,因此这些属性变化时需要修改相应的目录项(如文件重命名)
目录结构
单级目录结构,实现了“按名存取”,但是存在查找速度慢、文件不允许重名、不便于文件共享等缺点,不适合多用户的操作系统
两级目录结构
早期的多用户操作系统,采用两级目录结构。分为主文件目录(MFD)和用户文件目录(UFD)。
两级目录结构提高了检索的速度,解决了多用户之间文件重名问题,文件系统可以在目录上实现访问限制。但是两级目录结构缺乏灵活性,不能对文件分类
树形目录结构,将两级目录结构进行推广就形成了树形目录结构。在树形目录结构中,用户可以通过绝对路径从根目录出发进行查找,也可以直接通过相对路径查找以减少读磁盘的IO操作的次数。目前大多数操作系统,如UNIX、Liunx、Windows都采用了树形文件目录
树形目录结构可以很方便地对文件进行分类,层次结构清晰,也能够更有效地进行文件的管理和保护。但是树形结构不便于实现文件的共享。为此,提出了“无环目录结构”
无环型图目录结构
可以用不同的文件名指向同一个文件,甚至可以指向同一个目录(共享目录下的所有内容)
需要为每个共享结点设置一个共享计数器,用于记录此时有多少个地方在共享结点。用户提出删除结点时,只是删除该用户的FCB、并使共享计数器减一,并不会直接删除共享结点。只有当共享计数器减为0时,才删除结点
共享文件不同于复制文件。在共享文件中,由于各用户指向的是同一个文件,因此只要其中一个用户修改了文件数据,那么所有用户都可以看到文件数据的变化
索引结点
文件目录通常存在磁盘上,当文件很多的时,文件目录会占用大量的盘块。在查找目录的过程中,要先将存放目录文件的第一个盘块中的目录调入内存,然后用给定的文件名逐一比较,若未找到指定文件,就还需要将下一个盘块中的目录调入内存,继续比较。也就是说,在检索文件时,文件的其他描述信息不会用到,也不需要调入内存,因此有的系统如UNIX便采用了文件名和文件描述信息分开的方法,使得文件描述信息单独形成一个称为索引结点的数据结构。简称i结点
,在文件目录中的每个目录仅由文件名和指向该文件所对应的i结点的指针构成
磁盘索引结点
磁盘索引节点是指存放在磁盘上的索引结点。每个文件有一个唯一的磁盘索引结点,主要包含以下内容:
- 文件主标识符,拥有文件的个人或小组的标识符
- 文件类型,包括普通文件、目录文件或者特别文件
- 文件存取权限,各类用户对该文件的存取权限
- 文件物理地址,每个索引节点中含有13个地指项,用于给出数据文件所在盘块的编号
- 文件长度,指文件以字节为单位的文件长度
- 文化链接数,在本文件系统中所有指向改文件的文件名的指针计数
- 文件存取时间,本文件最近的被存取的时间
内存索引结点
是指存放在内存中的索引结点。当文件被打开时,要将磁盘索引结点拷贝到内存的索引结点中,便于以后使用。在内存索引结点中增加了以下内容:
- 索引结点编号,用于标识内存索引结点
- 状态,指示该结点是否被修改
- 访问计数,当有进程访问该结点时计数器+1,访问结束时-1
- 逻辑设备编号,文件所属文件系统的逻辑设备编号
- 链接指针,设置分别指向空闲链表和散列队列的指针
文件存储的空间管理
该部分内容讲的是如何管理磁盘中空闲的空间,以及如何给文件分配空间
文件存储设备分成许多个大小相同的物理块,并以块为单位交换信息,因此文件的存储设备的管理实质上是对空闲块的组织和管理,它包括空闲块的组织、分配与回收等问题
安装WIndows操作系统的时候,需要为磁盘分区(C:盘、D:盘、E:盘)也就是不同的文件卷,即将一个物理磁盘划分为多个逻辑磁盘,当然也有将多个物理磁盘划分为一个逻辑磁盘。
存储空间的初始化将各个文件卷划分为目录区和文件区。
- 文件区用于存放文件数据
- 目录区主要存放文件的目录信息FCB、用于磁盘存储空间的管理信息
空闲表法
实现方式:为磁盘建立一个空闲盘块表,其中的每一个表项中含有第一个空闲盘块号、空闲盘块数
,对应的含义就是这片连续的盘块的第一块以及有几块连续空闲
空闲表法适用于连续分配方式。如何分配磁盘:与内存管理的动态分区分配类似,为一个文件分配连续的存储空间。同样可采用首次适应算法、最佳适应算法、最坏适应算法等来决定要为文件分配哪个区间
如何回收磁盘块:与内存管理中的动态分区分配类似,当回收某个存储区的时候有四种情况:①回收区的前后都没有相邻空闲区;②回收区的前后都是空闲区;③回收区前面是空闲区;④回收区的后面是空闲区
空闲链表法
空闲链表法也可以分为空闲盘块链和空闲盘区链。
空闲盘块链。将磁盘上的所有空闲空降以盘块为单位拉成一条链。当用户因创建文件而请求分配存储空间时,从链首开始依次给用户分配空闲盘块。当用户因删除文件而释放存储空间时,系统将回收的盘块依次插入空闲盘块链的末尾
空闲盘区链。将磁盘上的所有空闲分区(每个盘区可包含若干个块)拉成一条链。每个盘区需要除了给出下一个空闲盘区外还需要,指明本盘区大小的信息。分配盘区的方法与内存的动态分配类似,通常采用首次适应算法。当用户因删除文件而释放释放存储空间时,将对应的盘区挂到空闲盘区链的末尾,在可合并时也需要考虑合并。
✨✨位示图法
位示图法是利用二进制的一位来表示磁盘中一个盘块的使用情况,磁盘上所有的盘块都有一个二进制位与之对应。而用0
、1
来表示盘块是否已分配。在位示图中的每一行对应一个字,没列对应一个字中的一位。(要注意位示法的初始编号是0还是1)
如何分配:若文件需要K个块,①顺序扫描位示图,找到K个相邻或者不相邻的“0”(即空闲块);②根据字号、位号算出对应的盘块号,将相应的盘块分配给文件;③将相应的位设置为“1”
如何回收:①根据回收的盘块号计算对应的字号、位号;②将相应二进制位设为“0”
成组链接法
空闲表法、空闲链表法不适用于大型的文件系统,因为空闲表或空闲链可能过大。UNIX系统中采用了成组链接法对磁盘空闲块进行管理。
文件卷的目录区中专门设置一个磁盘作为“超级块”,当系统启动时需要将超级块读入内存,并且保证内存与外存中的“超级块”数据一致
成组链接法的大致思想是:把顺序的n个空闲盘块号保存在第一个成组链块中,其最后一个空闲盘块(作为成组链接块),则用于保存另一组空闲盘号,如此继续将所有空闲盘块均予以链接,若已经没有下一组空闲块,则设置为特殊值
怎么分配:
根据第一个成组链块的执政,将其对应的盘块分配给用户,然后将指针下移一格。若该指针指向的是最后一个盘块(即成组链块),因此要将该盘块读入内存,并将指针指向新的成组链块的第一条记录,然后执行上述分配操作
盘块的回收:
当第一个分组还未满的时候,直接将回收的盘块插入第一个分组中。当第一个分组已经满的时候,需要将超级块中的数据复制到新回收的块中,并修改超级块的内容,让新回收的块成为第一个分组
文件的基本操作
创建文件
进行Create系统调用时,需要提供几个主要参数:
- 所需的外存空间大小(如:一个盘块,即1KB)
- 文件存放路径(“D:/Demo”)
- 文件名
操作系统在处理Create系统调用时,主要做了两件事情:
- 在外存中找到文件所需的空间(结合前面的文件存储空间管理中的空闲链表法、位示图、成组链接法等管理策略,找到空闲空间)
- 根据文件存放路径的信息找到该文件目录对应的目录文件(例如D:/Demo目录),在目录中创建该文件对应的目录项。目录中包含了文件名,文件在外存中的存放位置等信息
删除文件
进行Delete系统调用时,须要提供几个主要参数:
- 文件存放路径(“D:/Demo”)
- 文件名(“test.txt”)
操作系统在处理Delete系统调用时,主要做了几件事情:
- 根据文件存放路径找到相应的目录文件,从目录中找到文件名对应的目录项。
- 更久目录项记录的文件在外存中的存放位置、未见大小等信息,回收文件占用的磁盘块
- 从目录表中删除文件对应的目录项
三步走:找到对应目录,根据目录删除磁盘中的存储,删除相应目录
✨✨打开文件
在很多操作系统中,在对文件进行操作之前,要求用户先使用open系统调用“打开文件”,需要提供的几个参数:
- 文件存放路径(“D:/Demo”)
- 文件名(“test.txt)
- 要对文件的操作类型(如:r只读;rw读写等)
操作系统在处理open系统调用时,主要做了几件事情:
- 根据文件存放路径找到相应的目录文件,从目录中找到文件名对应的目录项(清除绝对路径访问和相对路径访问),并检查用户是否有指定的操作权限。
- 将目录项复制到内存中的“打开文件表”中。对应表目的编号(“索引号”也叫“文件描述符”)返回给用户。之后用户使用打开文件表的编号来指明要操作的文件
注意打开文件时并没有将文件的内存复制到内存
在多道程序系统中,用户进程和系统会分别维护打开文件表。如下图所示,可以容易看出系统维护的打开文件表和用户进程维护的打开文件表的差别。系统的打开文件表中的每项中有一个打开计数器
用于表示还有进个进程正打开文件。用户进的打开文件表中的表项中包含读写指针和访问权限,读写指针指明了读写进行的位置。
关闭文件
操作系统在处理Close系统调用时,主要做的几件事:
- 将进程的打开文件表相应表项删除
- 回收分配给该文件的内存空间等资源
- 系统打开文件表的打开计数器
count-1
,若count=0
则删除对应表项
读文件
执行读文件操作前先使用打开文件系统调用。进程使用read系统调用。需要指明是哪个文件,还需指明要读入多少数据、指明读入数据要放在内存的什么位置
操作系统在处理read系统调用时,会从读指针指向的外存中,将用户指定大小的数据读入用户指定的内存区域中。
写文件
执行完打开文件系统调用。进程使用write系统调用完成写操作,需要指明是哪个文件,(支持“打开文件”操作的系统中,只需提供文件在打开文件表中的索引号即可(无需文件名))、还需要指明要写多少数据、写回外存的数据放在内存中的什么位置
操作系统在处理write系统调用时,会从用户指定的内存区域中,将指定大小的数据写回执政指向的外存
文件共享
多个用户共享一个文件,意味着系统中只有“一份”文件数据。并且只要某个用户修改了该文件的数据,其他用户也可以看到文件数据的变化
如果是多个用户都“复制”了同一个文件,那么系统中会有“多份”文件数据。其中一个用户修改了自己的那份数据,对其他用户的文件数据并没有影响
基于索引结点的共享方式
硬链接.在这种共享方式中,诸如文件的物理地址及其他的文件属性等信息,不再放在目录项中,而放在索引节点中。在文件的目录中只设置文件名及指向相应索引结点的指针。在索引结点中设置一个链接计数count
,用于表示链接到本索引接文件结点上的用户目录项数目。只有没有文件链接一个共享文件时,即索引节点的链接计数器为0
。改文件才会被删除
利用符号链接实现文件共享
软连接。可以由操作系统创建一个LINK类型的新文件。当用户要读LINK类型文件时,操作系统会根据文件中的路径去找到链接的文件,然后再进行读从而实现文件的共享。实际上当其他用户在访问的时候,是通过LINK文件中保存的对应文件的绝对路径去访问。因此操作系统会根据文件的路径名逐个查找目录,即访问该文件一般需要多次读盘。
在利用符号链接方式实现文件共享时,只有文件主才拥有指向其索引结点的指针。而共享的该文件的其他用户只有改文件的路径名,并不拥有指向其索引节点的指针。所以当文件主删除一个共享文件后,其他用户又试图通过符号链接去访问它,则会访问失败。
注意:软链接在创建时,引用计数直接复制。它的引用计数与目标的文件的引用计数独立
参考
- 《王道24 考研复习指导》
- 《计算机操作系统 第四版》