操作系统-文件管理

文件的属性

文件名:由创建文件的用户决定文件名,主要说为了方便用户找到文件,同一个目录下不允许有重名文件。

标识符:一个系统内的各文件标识符唯一,对用户来说毫无可读性,因此标识符只是操作系统用于区分各个文件的一种内部名称。

类型:指明文件的类型

位置:文件存放的路径(让用户使用)、在外存中的地址(操作系统使用,对用户不可见)

大小:指明文件大小

创建时间、上次修改时间、文件所有者信息

保护信息:对文件进行保护的访问控制信息
文件分类

无结构文件(如文本文件)--由一些二进制或字符流组成,又称"流式文件"

有结构文件(如数据库表)--由一组相似的记录组成,又称"记录式文件"
操作系统向上提供的基本功能

  • 创建文件(create系统调用)
  • 删除文件(delete系统调用)
  • 读文件(read系统调用)
  • 写文件(write系统调用)
  • 打开文件(open系统调用)
  • 关闭文件(close系统调用)

文件的逻辑结构

所谓的"逻辑结构",就是指在用户看来,文件内部的数据应该是如何组织起来的。而"物理结构"指的是在操作系统看来,文件的数据是如何存放在外存中的。

有结构文件

由一组相似的记录组成,又称"记录式文件"。每条记录由若干数据项组成。

如:数据库表文件。一般来说,每条记录有一个数据项可作为关键字。

根据各条记录的长度(占用的存储空间)是否相等,又可分为定长记录和可变长记录两种。

顺序文件

顺序文件:文件中的记录一个接一个地顺序排列(逻辑上),记录可以是定长的或可变长的。

各个记录在物理上可以顺序存储或链式存储

顺序存储--逻辑上相邻的记录物理上也相邻

链式存储--逻辑上相邻的记录物理上不一定相邻(类似于链表)

结论:定长记录的顺序文件,若物理上采用顺序存储,则可实现随机存取;若能再保证记录的顺序结构,则可实现快速检索(即根据关键字快速找到对应记录)

注:一般,考题中所说的"顺序文件"指的是物理上顺序存储的顺序文件。顺序文件的缺点说增加/删除一个记录比较困难(如果说串结构则相对简单)

索引文件

索引表本身是定长记录的顺序文件。因此可以快速找到第i个记录对应的索引项。

可将关键字作为索引号内容,若按关键字顺序排列,则还可以支持按照关键字折半查找。

每当要增加/删除一个记录时,需要对索引表进行修改。由于索引文件有很快的检索速度,因此主要用于对信息处理的及时性要求比较高的场合。

索引顺序文件

索引顺序文件是索引文件和顺序文件思想的结合。索引顺序文件中,同样会为文件建立一张索引表,但不同的是:并不是每个记录对应一个索引表项,而是一组记录对应一个索引表项。


文件目录

文件控制块

目录本身就是一种有结构文件,由一条条记录组成。每条记录对应一个在该放在该目录下的文件

目录文件中的一条记录就是一个"文件控制块(FCB)"

FCB的有序集合称为"文件目录",一个FCB就是一个文件目录项。

FCB中包含了文件的基本信息(文件名、物理地址、逻辑结构、物理结构等),存取控制信息(是否可读/可写、禁止访问的用户名单等),使用信息(如文件的建立时间、修改时间等)。

FCB实现了文件名和文件之间的映射。使用户(用户程序)可以实现"按名存取"
需要对目录进行的操作:

搜索:当用户要使用一个文件时,系统要根据文件名搜索目录,找到该文件对应的目录项

创建文件:创建一个新文件时,需要在其所属的目录中增加一个目录项

删除文件:当删除一个文件时,需要在目录中删除相应的目录项

显示目录:用户可以请求显示目录的内容,如显示该目录中的所有文件及相应属性

修改目录:某些文件属性保存在目录中,因此这些属性变化时需要修改相应的目录项(如:文件重命名)

目录结构--单级目录结构

早期操作系统并不支持多级目录,整个系统中只建立一张目录表,每个文件占一个目录项。

单级目录实现了"按名存取",但是不允许文件重名

在常见一个文件时,需要先检查目录表中有没有重名文件,确定不重名后才能允许建立文件,并将新文件对应的目录项插入目录表中。

显然,单级目录结构不适用于多用户操作系统。

目录结构--两级目录结构

早期的多用户操作系统,采用两级目录结构。分为主文件目录(MFD,Master File Directory)和用户文件目录(UFD,User Flie Directory).

目录结构--多级目录结构(树形目录结构)

用户(或用户进程)要访问某个文件时要用文件路径名标识文件,文件路径名是个字符串。各级目录之间用"/"隔开。从根目录出发的路径称为绝对路径。

如:xx.jpg的绝对路径是"/zp/2015/xx.jpg"

系统根据绝对路径一层一层地找到下一级目录。刚开始从外存读入根目录的目录表;找到"zp"目录的存放位置后,从外存读入对应的目录表;再找到"2015"目录的存放位置,再从外存读入对应目录表;最后才找到文件"xx.jpg"的存放位置。整个过程需要3次读磁盘I/O操作。

很多时候,用户会连续访问同一目录内的多个文件(比如:接连查看"2015"目录内的多个文件),显然,每次都从根目录开始查找,是很低效的。因此可以设置一个"当前目录"

如:此时已经打开了"照片"的目录文件,也就是说,这张目录表已调入内存,那么可以把它设置为"当前目录"。当用户想要访问某个文件时,可以使用从当前目录出发的"相对路径"。

在Linux中,"."表示当前目录,因此如果"zp"是当前目录,则"xx.jpg"的相对路径为:"./2015/xx.jpg"。从当前路径出发,只需要查询内存中的'zp'目录表,即可知道'2015'目录表存放位置,从外存调入该目录,即可真的'xx.jpg'存放的位置了。

可见,引入"当前目录"和"相对路径"后,磁盘I/O的次数减少了。这就提升了访问文件的效率。

树形目录结构可以很方便地对文件进行分类,层次结构清晰,也能够更有效地进行文件的管理和保护。但是,树形结构不便于实现文件的共享。为此,提出了"无环图目录结构"。

目录结构--无环图目录结构

可以用不同的文件名指向同一个文件,甚至可以指向同一个目录(共享同一个目录下的所有内容)

需要为每个共享结点设置一个共享计数器,用于记录此时有多少个地方在共享该结点。用户提出删除结点的请求时,只是删除该用户的FCB、并使共享计数器减1,并不会直接删除共享结点。

注意:共享文件不同于复制文件。在共享文件中,由于各用户指向的是同一个文件,因此只要其中一个用户修改了文件数据,那么所有用户都可以看到文件数据的变化。

索引结点(FCB的改进)

索引结点:除了文件名之外的文件描述信息都放到这里来

假设一个FCB是64B,磁盘块的大小为1KB,则每个盘块中只能存放16个FCB。若一个文件目录中共有640个目录项,则共需要占用640/16 = 40 个盘块。因此按照某文件名检索该目录,平均需要查询320 个目录项,平均需要启动磁盘20次(每次磁盘I/O读入一块)。

若使用索引结点机制,文件名占14B,索引结点指针站2B,则每个盘块可存放64个目录项,那么按文件名检索目录平均只需要读入 320/64 = 5 个磁盘块。显然,这将大大提升文件检索速度。

当找到文件名对应的目录项时,才需要将索引结点调入内存,索引结点中记录了文件的各种信息,包括文件在外存中的存放位置,根据"存放位置"即可找到文件。

存放在外存中的索引结点称为"磁盘索引结点",当索引结点放入内存后称为"内存索引结点"。相比之下内存索引结点中需要增加一些信息,比如:文件是否被修改、此时有几个进程正在访问该文件等。

文件的物理结构(文件分配方式)

文件块、磁盘块

类似于内存分页,磁盘中的存储单元也会被分为一个个"块/磁盘块/物理块"。很多操作系统中,磁盘块的大小与内存块、页面的大小相同

在内存管理中,进程的逻辑地址空间被分为一个一个页面

同样的,在外存管理中,为了方便对文件数据的管理,文件的逻辑地址空间也被分为了一个一个的文件"块"。

于是文件的逻辑地址也可以表示为(逻辑块号,块内地址)的形式。

操作系统为文件分配存储空间都是以块为单位的

用户通过逻辑地址来操作自己的文件,操作系统要负责实现从逻辑地址到物理地址的映射

文件分配方式--连续分配

连续分配方式要求每个文件在磁盘上占有一组连续的块

优点:支持顺序访问和直接访问(即随机访问);连续分配的文件在顺序访问时速度最快

缺点:不方便文件拓展;存储空间利用率低,会产生磁盘碎片

用户通过逻辑地址来操作自己的文件,操作系统如何实现从逻辑地址到物理地址的映射?

(逻辑块号,块内地址)->(物理块号,块内地址)。只需转换块号就行,块内地址保持不变。

用户给出要访问的逻辑块号,操作系统找到该文件对应的目录项(FCB)...

物理块号=起始块号+逻辑块号

当然,还需要检查用户提供的逻辑块号是否合法(逻辑块号>=长度就不合法)

可以直接算出逻辑块号对应的物理块号,因此连续分配支持顺序访问和直接访问(即随机访问)

读取某个磁盘块时,需要移动磁头。访问的两个磁盘块相隔越远,移动磁头所需时间就越长。

结论:连续分配的文件在顺序读/写时速度最快

物理上采用连续分配的文件不方便拓展。

物理上采用连续分配,存储空间利用率低,会产生难以利用的磁盘碎片

可以用紧凑来处理碎片,但是需要耗费很大的时间代价。

文件分配方式--链接分配

链接分配采取离散分配的方式,可以为文件分配离散的磁盘块。分为隐式链接和显式链接两种。

链接分配--隐式链接

用户给出要访问的逻辑块号i,操作系统找到文件对应的目录项(FCB)...

从目录项中找到起始块号(即0号块),将0号逻辑块读入内存,由此知道1号逻辑块存放的物理块号,于是读入1号逻辑块,再找到2号逻辑块的存放位置...以此类推。

因此,读入i号逻辑块,总共需要i+1次磁盘I/O。

结论:采用链式分配(隐式链接)方式的文件,只支持顺序访问,不支持随机访问,查找效率低。另外,指向下一个盘块的指针也需要耗费少量的存储空间。

采用隐式链接的链接分配方式,很方便文件扩展。另外,所有的空闲磁盘块都可以被利用,不会有碎片问题,外存利用率高。

隐式链接------除文件的最后一个盘块之外,每个盘块中都存有指向下一个盘块的指针。文件目录包括文件第一块的指针和最后一块的指针。

优点:很方便文件拓展,不会有碎片问题,外存利用率高。

缺点:只支持顺序访问,不支持随机访问,查找效率低,指向下一个盘块的指针也需要耗费少量的存储空间

链接分配--显式链接

把用于链接文件各物理块的指针显式地存放在一张表中。即 文件分配表(FAT,File Allocation Table)
用户给出要访问的逻辑块号 i,操作系统找到该文件对应的目录项(FCB)...

从目录项中找到起始块号,若i>0,则查询内存中的文件分配表FAT,往后找到i号逻辑块对应的物理块号。逻辑块号转换成物理块号的过程不需要读磁盘操作。

结论:采用链式分配(显式链接)方式的文件,支持顺序访问,也支持随机访问(想访问i号逻辑块时,并不需要依次访问之前的0~i-1i-1号逻辑块),由于块号转换的过程不需要访问磁盘,因此相比于隐式链接来说,访问速度快很多。

显然,显式链接也不会产生外部碎片,也可以很方便地对文件进行拓展。

显式链接------把用于链接文件各物理块的指针显式地存放在一张表中,即 文件分配表(FAT,FileAllocation Table)。一个磁盘只会建立一张文件分配表。开机时文件分配表放入内存,并常驻内存。

优点:很方便文件拓展,不会有碎片问题,外存利用率高,并且支持随机访问。相比于隐式链接来说,地址转换时不需要访问磁盘,因此文件的访问效率更高。

缺点:文件分配表的需要占用一定的存储空间。

文件分配方式--索引分配

索引分配允许文件离散地分配在各个磁盘块中,系统会为每个文件建立一张索引表,索引表中记录了文件的各个逻辑块对应的物理块(索引表的功能类似于内存管理中的页表--建立逻辑页面到物理页之间的映射关系)。索引表存放的磁盘块称为索引块。文件数据存放的磁盘块称为数据块。

任何实现文件的逻辑块号到物理块号的转换?

用户给出要访问的逻辑块号i,操作系统找到该文件对应的目录项(FCB)...

从目录项中可知索引表存放位置,将索引表从外存读入内存,并查找索引表即可只i号逻辑块在外存中的存放位置。

可见,索引分配方式可以支持随机访问。文件扩展也很容易实现(只需要给文件分配一个空闲块,并增加一个索引表项即可)

若每个磁盘块1KB,一个索引表项4B,则一个磁盘块只能存放256个索引项。

如果一个文件的大小超过了256块,那么一个磁盘块是装不下文件的整张索引表的,如何解决这个问题?

  • 链接方案
  • 多层索引
  • 混合索引

链接方案:如果索引表太大,一个索引块装不下,那么可以将多个索引块链接起来存放


多层索引:建立多层索引(原理类似于多级页表)。使第一层索引块指向第二层的索引块。还可根据文件大小的要求再建立第三层、第四层索引块

若采用三层索引,则文件的最大长度为256256 256*1KB=16GB

类似的,访问目标数据块,需要4次磁盘I/O

采用K层索引结构,且顶级索引表未调入内存,则访问一个数据块只需要K+1次读磁盘操作
混合索引:多种索引分配方式的结合。例如,一个文件的顶级索引表中,既包含直接地址索引(直接指向数据块),又包含一级间接索引(指向单层索引表)、还包含两级间接索引(指向两层索引表)


逻辑结构VS物理结构


逻辑结构(从用户视角看)

物理结构(从操作系统视角看)


例:c语言创建顺序文件

物理结构(从操作系统视角看)




链式存储的顺序文件采用连续分配

链式存储的顺序文件采用链接分配

逻辑结构:索引文件

索引文件采用索引分配

文件存储空间管理

存储空间的划分与初始化

安装Windows操作系统的时候,一个必须步骤是--为磁盘分区(C盘,D盘,E盘等)

存储空间的划分:将物理磁盘划分为一个个文件卷(逻辑卷、逻辑盘)

存储空间管理--空闲表法(适用于"连续分配方式")

如何回收磁盘块:与内存管理中的动态分区分配很类似,当回收某个存储区时需要有四种情况

  1. 回收区的前后都没有相邻空闲区
  2. 回收区的前后都是空闲区
  3. 回收区前面是空闲区
  4. 回收区后面是空闲区

总之,回收时需要注意表项的合并问题
存储空间管理--空闲链表法





存储空间管理--成组链接法

如何分配?

需要1个空闲块

  1. 检查第一个分组的块数是否足够。1<100,因此是足够的
  2. 分配第一个分组中的1个空闲块,并修改相应数据

需要100个空闲块

  1. 检查第一个分组的块数是否足够。100=100,是足够的
  2. 分配第一个分组中的100个空闲块。但是由于300号块内存放了再下一组的信息,因此300号块的数据需要复制到超级块中


如何回收?

假设每个分组最多为100个空闲块,此时第一个分组已有99个块,还要再回收一块

需要将超级块中的数据复制到新回收的块中,并修改超级块的内容,让新回收的块成为第一个分组

文件的基本操作

创建文件

进行create系统调用时,需要提供的几个主要参数:

  1. 所需的外存空间大小(如:一个盘块,即1KB)
  2. 文件存放路径("D:/Demo")
  3. 文件名

操作系统在处理create系统调用时,主要做了两件事:

  1. 在外存中找到文件所需的空间(结合上小节学习的空闲链表法、位示图、成组链接法等管理策略,找到空闲空间)
  2. 根据文件存放路径的信息找到该目录对应的目录文件,在目录中创建文件电影的目录项。目录项中包含了文件名、文件在外存中的存放位置等信息。

删除文件

进行delete系统调用时,需要提供的几个主要参数:

  1. 文件存放路径
  2. 文件名

操作系统在处理delete系统调用时,主要做了几件事:

  1. 根据文件存放路径找到相应的目录文件,从目录中找到文件名对应的目录项
  2. 根据该目录项记录的文件在外存的存放位置、文件大小等信息,回收文件占用的磁盘块。(回收磁盘块时,根据空闲表法、空闲链表法、位图法等管理策略的不同,需要做不同的处理)
  3. 从目录表中删除文件对应的目录项

打开文件

在很多操作系统中,在对文件进行操作之前,要求用户先使用open系统调用"打开文件",需要提供的几个主要参数:

  1. 文件存放路径
  2. 文件名
  3. 要对文件的操作类型

操作系统在处理open系统调用时,主要做了几件事:

  1. 根据文件存放路径找到相应的目录文件,从目录中找到文件名对应的目录项,并检查该用户是否有指定的操作权限
  2. 将目录项复制到内存中的"打开文件表"中。并将对应表目的编号返回给用户。之后用户使用打开文件表的编号来指明要操作的文件。


关闭文件

进程使用完文件后,要"关闭文件"

操作系统在处理Close系统调用时,主要做了:

  1. 将进程的打开文件表相应表项删除
  2. 回收分配给该文件的内存空间等资源
  3. 系统打开文件表的打开计数器count减1,若count=0,则删除对应表项

读文件

进程使用read系统调用完成写操作。需要指明是哪个文件,还需指明要读入多少数据、指明读入的数据要放在内存中的什么位置。

操作系统在处理read系统调用时,会从读指针指向的外存中,将用户指定大小的数据读入用户指定的内存区域中。
写文件

进程使用write系统调用完成写操作,需要指明是哪个文件,还需要指明要写出多少数据、写回外存的数据放在内存中的什么位置

操作系统在处理write系统调用时,会从用户指定的内存区域,将指定大小的数据写回写指针指向的外存。

文件共享

多个用户共享同一个文件,意味着系统中只有"一份"文件数据。并且只要某个用户修改了该文件的数据,其他用户也可以看到文件数据的变化。

如果是多个用户都"复制"了同一个文件,那么系统中会有"好几份"文件数据。其中一个用户修改了直接的那份文件数据,对其他用户的文件数据并没有影响。
基于索引结点的共享方式(硬链接)

索引结点中设置一个链接计数变量 count,用于表示链接到本索引结点上的用户目录项数。

若 count = 2,说明此时有两个用户目录项链接到该索引结点上,或者说是有两个用户在共享此文件。

若某个用户决定"删除"该文件,则只是要把用户目录中与该文件对应的目录项删除,且索引结点的count值减 1。

若 count>0,说明还有别的用户要使用该文件,暂时不能把文件数据删除,否则会导致指针悬空。

当 count = 0 时系统负责删除文件。
基于符号链的共享方式(软链接)

当 User3 访问"ccc"时,操作系统判断文件"ccc"属于 Link 类型文件,于是会根据其中记录的路径层层查找目录,最终找到 User1 的目录表中的"aaa"表项,于是就找到了文件1的索引结点。

文件保护

口令保护

为文件设置一个口令,用户请求访问该文件时必须提供口令

口令一般存放在文件对应的FCB或索引结点中。用户访问文件前需要先输入口令,操作系统会将用户提供的口令与FCB中存储的口令进行对比,如果正确,则允许该用户访问文件。

优点:保存口令的空间开销不多,验证口令的时间开销也很小。

缺点:正确的"口令"存放在系统内部,不够安全。

加密保护

使用某个"密码"对文件进行加密,在访问文件时需要提供正确的"密码"才能对文件进行正确的解密。

优点:保密性强,不需要在系统中存储"密码"

缺点:编码/译码,或者说加密/解密要花费一定时间

访问控制

在每个文件的FCB(或索引结点)中增加一个访问控制列表(Access-Control List,ACL),该表中记录了各个用户可以对该文件执行哪些操作。

有的计算机可能会有很多个用户,因此访问控制列表可能会很大,可以用精简的访问列表解决这个问题

精简的访问列表:以"组"为单位,标记各"组"用户可以对文件执行哪些操作。

如:分为 系统管理员、文件主、文件主的伙伴、其他用户 几个分组

文件系统的层次结构

用一个例子来辅助记忆文件系统的层次结构:

假设某用户请求删除文件 "D:/工作目录/学生信息.xlsx" 的最后100条记录。

  1. 用户需要通过操作系统提供的接口发出上述请求--用户接口
  2. 用于用户提供的是文件的存放路径,因此需要操作系统一层一层地查找目录,找到对应的目录项--文件目录系统
  3. 不同的用户对文件有不同的操作权限,因此为了保证安全,需要检查用户是否有访问权限--存取控制模块(存取控制验证层)
  4. 验证了用户的访问权限之后,需要把用户提供的"记录号"转变为对应的逻辑地址--逻辑文件系统与文件信息缓冲区
  5. 知道了目标记录对应的逻辑地址后,还需要转换成实际的物理地址--物理文件系统
  6. 要删除这条记录,必定要对磁盘设备发出请求--设备管理程序模块
  7. 删除这些记录后,会有一些盘块空闲,因此要将这些空闲盘块回收--辅助分配模块

文件系统的全局结构

原始磁盘

物理格式化后

物理格式化,即低级格式化--划分扇区,检测坏扇区,并用备用扇区替换坏扇区

逻辑格式化后


虚拟文件系统

普通文件系统

虚拟文件系统


虚拟文件系统



文件系统挂载

相关推荐
Rookie也要加油31 分钟前
01_SQLite
数据库·sqlite
liuxin3344556635 分钟前
教育技术革新:SpringBoot在线教育系统开发
数据库·spring boot·后端
看山还是山,看水还是。1 小时前
MySQL 管理
数据库·笔记·mysql·adb
fishmemory7sec1 小时前
Koa2项目实战2(路由管理、项目结构优化)
数据库·mongodb·koa
momo小菜pa2 小时前
【MySQL 09】表的内外连接
数据库·mysql
Jasonakeke2 小时前
【重学 MySQL】四十九、阿里 MySQL 命名规范及 MySQL8 DDL 的原子化
数据库·mysql
程序猿小D2 小时前
第二百六十九节 JPA教程 - JPA查询OrderBy两个属性示例
java·开发语言·数据库·windows·jpa
小宇成长录2 小时前
Mysql:数据库和表增删查改基本语句
数据库·mysql·数据库备份
团儿.3 小时前
解锁MySQL高可用新境界:深入探索MHA架构的无限魅力与实战部署
数据库·mysql·架构·mysql之mha架构
程序猿小D3 小时前
第二百六十七节 JPA教程 - JPA查询AND条件示例
java·开发语言·前端·数据库·windows·python·jpa