学习日期:2024.7.14
内容摘要:文件管理基础、文件的逻辑结构、文件目录
文件管理基础
引言
文件是一组有意义的信息/数据的集合,计算机中存放着各种各样的文件,一个文件有哪些属性?
操作系统应该向上层的应用程序提供什么功能方便用户和应用程序使用文件?文件应该如何存放在外存上?这一切都要依靠文件管理。
文件的属性
随便右击一个文件,选择属性,我们会看到这样的内容,这上面的就是文件的属性。
文件名:由用户命名,方便用户记忆。同一目录下不允许有重名文件(试图重名时,会自动加个(2)之类)
标识符:一个系统内的各文件标识符唯一,对用户来说无可读性,是操作系统用于区分文件的内部名称。
类型:指明文件的类型
位置:文件存放的路径(用户可见) 在外存中的地址(操作系统使用,对用户不可见)
大小:文件的大小
创建时间、修改时间、访问时间
流式文件与记录式文件
无结构文件(如文本文件)由一些二进制数字或字符组成,又称流式文件
而一些文件,如Excel表格等,显然是有结构的,由一组相似的记录组成,又称记录式文件
记录是一组相关数据项的集合,数据项是文件系统当中最基本的数据单位。
用人话说就是,一个填满个人信息的表格,每个小格子里的内容(年龄、性别、手机号等)就是一个数据项,一排小格子组成一行,就是一个人信息的记录,这么多人的记录组成的表格,就是一个记录式文件。
文件之间应该怎样组织
我们的电脑中有好几个“盘”,每个盘有很多文件夹,每个文件夹下面还有文件夹,或者直接存文件。设想一下,如果没有这些树状的目录组织,所有的文件全部都堆到一起,是不是很不方便?
用户可以自己创建一层一层的目录(就是我们说的“文件夹”),各层目录中存放相应的文件,系统中的各个文件就这样合理组织起来了。目录本身也是一种特殊的有结构文件。
操作系统向上提供的功能
怎么样新建一个文本文档?在想建的地方鼠标右键->新建->选择文本文档
这其实就是图形化交互进程在背后调用了create系统调用,建立了新文件。
接下来,我们只要双击就可以打开这个文件,编辑之后可以保存,不想要了还可以删除。
这是“记事本”应用程序通过操作系统提供的“读文件”功能,即read系统调用,将文件数据从外存读入内存,并显示在屏幕上。同样,也可以通过操作系统提供的“写文件”功能,即write系统调用,将文件数据从内存写回外存。
记不住的话,就想想新建一个文本文档,打开,编辑,然后保存再删除,都需要什么。
一些复杂的操作其实也是简单操作组成的,比如CV大法。“复制”其实就是新建一个空的新文件,然后把源文件读入内存,再将内存中的数据写到新文件当中。而“剪切”事实上是复制再删除,不是移动。这就是为什么使用读写速度快的固态硬盘复制文件更快,而机械硬盘较慢。
操作系统向下提供的功能
文件平时是保存在外存(就是我们说的“硬盘”)中的。类似于内存分为一个个内存块,外存也会分成一个个大小相等的磁盘块,每块一般包含2的整数次幂个地址,同样类似的是,文件的逻辑地址也可以分为逻辑块号和块内地址。
操作系统以块为单位分配存储空间,如果一个块的大小为1KB,即使文件更小,也要占一个完整的块。外存中的数据读入内存时同样以块为单位。
其它需要操作系统实现的文件功能
一台计算机上可能有多个“用户”,这就需要实现文件共享和文件保护
文件共享:使多个用户可以共享使用一个文件。
文件保护:保证不同的用户对文件有不同的操作权限。
文件的逻辑结构
所谓的“逻辑结构”是指用户视角中数据的结构,而“物理结构”是指在操作系统看来数据是如何存放在外存中的。
拿数据结构中的链表和数组举例子,这俩都属于线性表,在我们看来,它们的数据都是顺序存储,一个连着一个的,这就是“逻辑结构”相同。但是顺序表的各个元素在物理上也是相邻的,而链表的各个元素在物理上是不相邻的,这就是“物理结构”。
无结构文件又称流式文件,因为没有很明显的结构特性,所以不讨论逻辑结构问题。
学号 | 姓名 | 性别 | 专业 |
114513 | 张三 | 男 | 计算机科学与技术 |
114514 | 李四 | 男 | 计算器维修 |
114515 | 王五 | 女 | 人工智能 |
而上面这个就是一个典型的有结构文件,又称记录式文件。每个小格子里的内容(学号、姓名、性别、专业)就是一个数据项,一排小格子组成一行,就是一个人信息的记录,这么多人的记录组成的表格,就是一个记录式文件。
一般来说,在每条记录中有一个数据项可以作为关键字,作为识别不同记录的ID,在这个例子中就是学号。根据各条记录的长度是否相同,又分为定长记录和变长记录。
假如增加一栏学生自由选填的“特长”,因为不知道这个数据项的长度(可能没有),这条记录的长度就不确定,这就是变长记录。
有结构文件的逻辑结构分为顺序文件,索引文件,和索引顺序文件三种。
顺序文件
文件中的记录在逻辑上一个接一个的顺序排列,记录可以定长或变长,各个记录在物理上可以连续存储,也可以链式存储。(分别类似于顺序表和链表)一般来说,题目中所说的的“顺序文件”,指的就是物理上顺序存储的顺序文件。
同数据结构一样,如果顺序文件是链式存储的,无法实现随机存取,每次只能从第一个记录(表头)开始以此往后查找。
顺序存储的定长记录可以实现随机存取,因为记录长度为L,我们知道首地址,则第 i 个记录存放的位置只需要 首地址 +i*L 就行。
如果采用了串结构,意味着存储的关键字是乱的(虽然是顺序存储的,但是学号不是连着的),那么第 i 个记录不一定是第 i 个学生,就不能实现快速查找到某关键字对应的记录,而要遍历再比对。只有物理上顺序存储的顺序文件才能实现不遍历的快速查找。
顺序存储的可变长记录也无法实现随机存取,每次只能从第一个记录开始以此往后查找。因为记录长度是不固定的,我们不能用 i*L 计算地址。
优缺点也同顺序表和链表一样,顺序存储的缺点是增加/删除一个记录困难(需要全部移位),而链式存储修改更容易,但不能快速查找和随机存取。
索引文件
在上面我们了解到,对于可变长记录,要查找到第i个记录, 就必须顺序查找前面i-1个记录,实在麻烦,但是实际生活中我们经常需要用到可变长记录,那么如何解决?
索引表本身是一个定长记录的顺序文件,因此可以快速找到第 i 个记录对应的索引项。可将关键字作为索引号内容,如果按关键字顺序排列,则还可以按关键字二分查找。
这和我们之前在《内存管理》当中学过的分页式存储管理很相似,文件是可以离散保存的,但是页表(索引表)是在物理上顺序保存的。
每当要增加/删除记录时,需要对索引表进行修改,因为其检索速度很快,通常用于对信息处理的即时性要求很高的场合。
也可以用不同的数据项建立多个索引表,比如可以用姓名建立索引表,这样就可以根据姓名快速检索文件了。
索引顺序文件
索引文件确实很方便,但是每条记录都要对应一个索引项,还可能用不同的数据项建立多个索引表,这样下去,可能索引表比数据本身都大了,存一个32KB的文件要占64KB甚至更多的空间,索引表还必须连续存储,这不是很浪费空间吗?
即视感很强吧,这不就是——二级页表?
所以,我们引入了索引顺序文件,索引顺序文件中同样会为文件建立一张索引表,但不是每个记录都对应一个项,而是一组记录对应一个索引表项。
比如上图,左边是索引顺序文件,右边是逻辑文件。我们把学生名字按首字母顺序排好,每个索引顺序文件的地址再对应一个表。
假如一个变长顺序文件有2600个记录(每个名字首字母开头有100个人),根据关键字检索的话,我们每次从头开始遍历,平均需要查找1300次。
但是使用了索引顺序文件存储结构之后,我们首先遍历建立的26个分组,然后在每个分组内再顺序查找100个人,平均查找50次,这样平均每次只需要查找13+50=63次。
其实思路就是先粗定位到一部分,然后在这一部分中再依次遍历。
和二级页表一样,当记录过多时,可以继续套娃,称之为”多级索引表“。比如说一个文件有100 000个记录,我们可以分成100,100,100三层索引表,检索一个记录平均只需要50+50+50=150次,比全部遍历的平均50 000次快多了。
文件目录
在“文件之间应该怎样组织”部分中,我们提到了文件目录。这就是我们很熟悉的Windows操作系统的“文件夹”,那么这是怎么实现的呢?
文件控制块FCB
文件控制块FCB(File Control Block)
目录本身就是一种有结构文件,由一条条记录组成,每条记录对应一个在该目录下的文件。
当我们双击“照片”这个文件后,操作系统会从这个目录表中找到关键字“照片”对应的记录,然后将外存中“照片”的信息读入内存,于是,“照片”目录中的内容就可以显示出来了。
文件目录中的一条记录(表格的一行)就是一个文件控制块(FCB),FCB的集合就是文件目录。
FCB包含文件的基本信息(文件名、文件的物理地址、逻辑结构),存取控制信息(是否可读写,可以访问的用户名单),使用信息(文件的建立/修改时间)
需要对目录进行哪些操作?
搜索:当用户要使用一个文件时,系统要根据文件名搜索目录,找到对应的目录项。
创建/删除文件:创建/删除一个新文件时,要增加/删除相应的目录项。
显示目录:用户可以请求显示目录的内容,如显示文件的属性。
修改目录:在修改文件属性时,也需要修改相应的目录。(如重命名文件)
单级目录结构
早期操作系统不支持多级目录,整个系统中只建立一张目录表,每个文件占一个目录项。
单级目录实现了“按名存取”,但是不允许文件重名。此处的不允许,不是我们在“文件属性”里说的一个目录下不允许重名,是整个系统都不允许文件重名,这显然是不适用于多用户操作系统的。
两级目录结构
早期的多用户操作系统,采用两级目录结构。分为主文件目录(MFD,Master File Dictionary)和用户文件目录(UFD,User File Dictionary)。
两级目录允许不同用户的文件重名,也可以在目录上实现访问显示(不让用户访问其它用户的文件)但是两级目录依然缺乏灵活性,用户不能对自己的文件进行分类。
可以说,对于单个用户而言,两级目录结构和单级目录结构没有区别,就是对每个用户提供一个独立的单级目录结构。
多级目录结构
两级目录结构对于单个用户而言还是不方便,想象一下你的文件不能分类放到文件夹里面,而是全部堆在一起,找起来也太麻烦了。于是,就有了多级目录结构,又称树形目录结构。
其最大特点是不同目录下的文件可以重名,最经典的就是“新建文件夹”。你在哪儿都可以新建一个叫做“新建文件夹”的文件夹,但是在同一目录下,你会发现这个文件夹带了个(2)。
用户在访问某个文件时,要用文件路径名标识文件,文件路径名就是“E:\小说\重生之我是C++糕手”这样的字符串,像这样从根目录(CDE盘)出发的路径,称为绝对路径。
重生之我是C++糕手.txt 的绝对路径就是"E:\小说\网文\重生之我是C++糕手",就是你在打开文件时,文件夹上面那一行里面显示的内容。(当然这里不是txt,是个文件夹)
系统会根据绝对路径一层一层的找到下级目录,刚开始从外存读入根目录的目录表,再依次读入下一级目录的目录表,最后才找到文件的位置,整个过程读几次就需要几次I/O操作。
而很多时候用户会连续访问同一个目录下的文件,因此可以设置一个当前目录。当用户想要访问某个文件时,就使用从当前目录出发的相对路径。
比如如果当前目录是“小说”,则重生之我是C++糕手.txt 的相对路径为 \网文\重生之我是C++糕手,从当前目录出发,只需要查找内存中的“网文”目录表,就可以找到,I/O次数减少了,提升了访问文件的效率。
优缺点:树形目录可以很方便地对文件进行分类,层次结构清晰。但是,树形结构不便于实现文件共享。
无环图目录结构
为每个共享节点设置一个共享计数器,不同用户用不同的文件名指向同一个文件,当User1删除这个文件的时候,共享计数器减1。这样以用户1的视角来说,他把文件删除了,但是对用户2来说,他的文件还在。只有当共享计数器减为0,即没有用户需要这个节点时,才删除节点。
注意:共享文件不同于复制文件,在共享文件中,由于各用户指向的的同一个文件,只要一个用户修改了文件数据,所以用户都能看到变化。
FCB的改进
我们发现,在大多数情况下,那么大一块FCB都没有意义,我们只需要文件名用来查找目录就行了,不需要把那么多的信息全部存在FCB里面,因此我们可以对FCB进行简化。
我们把FCB简化为文件名和索引节点指针,指针指向对应的索引节点,每个文件都对应一个索引节点,里面存放原本的文件基本信息、存取控制信息、使用信息等等。
这样FCB会变小,虽然占用的总空间还是一样(甚至略大一点),但是每个盘块能能存放的目录项变多了,我们就更容易读到要查找的文件名。
这么说可能比较抽象,举个例子。比如说之前的方法,一个磁盘块能放10个FCB,若一个文件目录中有300个目录项,则需要占用30个盘块,因此按照某文件名查询该目录,平均要查150个目录项,进行15次I/O操作。
采用索引节点机制后,可能一个磁盘块中就能放60个FCB,只需要占用5个盘块,平均只需要进行2.5次I/O操作。我们知道I/O操作是很花时间的,这就节约了时间开销。
这和我们生活中查字典很相似,想想如果一个字典没有索引,而是把所有的字仅按照拼音首字母排列,是不是很闹心?我们用字典查一个字,先查偏旁部首,然后根据偏旁部首查字时,那些页不会给出要查的字的读音,意思,近义词等等细节信息,而是只有一堆字本身,方便你检索,你看到之后,再翻到对应的页码,看它的具体意思和遣词造句。
这就好比优化后的FCB和索引节点,如果不优化,就是你对着字典直接翻找,虽然肯定能找到,但是I/O成本就太高了。
感谢您看到这里,如果满意的话麻烦您点个赞支持一下,个人主页还有更多内容分享。
个人能力不足,如有错漏还请指出,我会尽快修改。
内容总结自王道计算机考研《操作系统》 和 人民邮电出版社《操作系统导论》