操作系统(13)-----文件管理2

简介: 操作系统(13)-----文件管理

操作系统(13)-----文件管理1:https://developer.aliyun.com/article/1511174

索引顺序文件的索引项也不需要按关键字顺序排列,这样可以极大地方便新表项的插入。并且索引顺序表的表项也少了许多。

所以索引文件是定长记录的顺序结构的顺序文件,而索引顺序文件是定长记录的串结构的顺序文件。

用这种策略确实可以让索引表“瘦身”,但是是否会出现不定长记录的顺序文件检索速度慢的问题呢?


一个顺序文件有10000个记录,则根据关键字检索文件,只能从头开始顺序查找(这里指的并不是定长记录、顺序结构的顺序文件),平均须查找 5000 个记录。


若采用索引顺序文件结构,可把10000个记录分为10000−−−−−√10000=100 组,每组 100个记录。则需要先顺序查找索引表找到分组(共100个分组,因此索引表长度为100,平均需要查50次),找到分组后,再在分组中顺序查找记录(每个分组100个记录,因此平均需要查50次)。可见,采用索引顺序文件结构后,平均查找次数减少为 50+50=100 次。


同理,若文件共有 10^6个记录,则可分为1000个分组,每个分组1000个记录。根据关键字检索一个记录平均需要查找 500+500=1000次。这个查找次数依然很多,如何解决呢?

多级索引顺序文件:

为了进一步提高检索效率,可以为顺序文件建立多级索引表。例如,对于一个含 106个记录的文件,可先为该文件建立一张低级索引表,每100个记录为一组,故低级索引表中共有10000个表项(即10000个定长记录),再把这10000个定长记录分组,每组100个,为其建立顶级索引表,故顶级索引表中共有100个表顶。


所以顶级索引表中有100个表项,低级索引表每个索引表也有100个表项,每个表项对应多个分组,每个分组中又会对应100个记录。此时,检索一个记录平均需要查找


50+50+50=150 次

四.文件之间应该怎样组织起来

下图的目录就是“文件夹”,用户可以自己创建一层一层的目录,各层目录中存放相应的文件。系统中的各个文件就通过一层一层的目录合理有序的组织起来了。

目录其实也是一种特殊的有结构文件(由记录组成),那么如何实现目录呢?、

五.文件的基本操作

文件的基本操作,也就是操作系统可以向上提供的功能:

1.创建文件(create系统调用)

可以“创建文件”,(点击新建后,图形化交互进程在背后调用了“create 系统调用”)

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


1.所需的外存空间大小(如:一个盘块,即1KB)


2.文件存放路径(“D:/Demo”)


3.文件名(这个地方默认为"新建文本文档.txt")


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

1.在外存中找到文件所需的空间(结合空闲链表法、位示图、成组链接法等管理策略,找到空闲空间)

2.根据文件存放路径的信息找到该目录对应的目录文件(此处就是D:/Demo目录),在目录中创建该文件对应的目录项。目录项中包含了文件名、文件在外存中的存放位置等信息。

2.删除文件(delete系统调用)

可以“删除文件”(点了“删除”之后,图形化交互进程通过操作系统提供的“删除文件”功能,即 delete 系统调用,将文件数据从外存中删除)

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


1.文件存放路径(“D:/Demo”


2.文件名(“test.txt”)

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

1.根据文件存放路径找到相应的目录文件,从目录中找到文件名对应的目录项。

2.根据该目录项记录的文件在外存的存放位置、文件大小等信息,回收文件占用的磁盘块。(回收磁盘块时,根据空闲表法、空闲链表法位图法等管理策略的不同,需要做不同的处理)


3.从目录表中删除文件对应的目录项。

3.读文件(read系统调用)

可以“读文件”,将文件数据读入内存,才能让CPU处理(双击后,“记事本”应用程序通过操作系统提供的“读文件”功能,即 read 系统调用,将文件数据从外存读入内存,并显示在屏幕上)

进行 read 系统调用时:

1.需要指明是哪个文件(在支持“打开文件”操作的系统中,只需要提供文件在打开文件表中的索引号即可)。

2.还需要指明要读入多少数据(如:读入1KB)。

3.指明读入的数据要放在内存中的什么位置。

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

4.写文件(write系统调用)

可以“写文件”,将更改过的文件数据写回外存(我们在“记事本”应用程序中编辑文件内容,点击“保存”后,“记事本”应用程序通过操作系统提供的“写文件”功能,即 write 系统调用,将文件数据从内存写回外存)

进行 write 系统调用时:

1.需要指明是哪个文件(在支持“打开文件”操作的系统中,只需要提供文件在打开文件表中的索引号即可)

2.还需要指明要写出多少数据(如:写出1KB)

3.写回外存的数据放在内存中的什么位置

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

注:对于"读/写文件"用“文件描述符”(即这一文件在内存中的打开文件表的索引号)即可指明文件,不再需要用到“文件名。

5.打开文件(open系统调用)

可以“打开文件”(读/写文件之前,需要“打开文件”,即open系统调用)这和用户双击触发的read系统调用不同。


只有读文件时才会将文件数据从外存读入内存,继续看就知道了。


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


1.文件存放路径(“D:/Demo”)


2.文件名(“test.txt”)


3.要对文件的操作类型(如:r只读;rw 读写等)


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

1.根据文件存放路径找到相应的目录文件,从目录中找到文件名对应的的目录项,同时不同用户对文件的操作权限不同,这些信息记录在目录项中,系统会根据目录项检查该用户是否有指定的操作权限。

若用户有指定的操作权限,则将目录项复制到内存中的“打开文件表”中(打开文件时并不会把文件数据直接读入内存,而是将目录项复制到内存的“打开文件表”)。系统会将文件的索引号(这个“索引号”,也称“文件描述符”)返回给用户。之后用户使用打开文件表的索引号来指明要操作的文件,即之后用户进程再操作文件就不需要每次都重新查目录了,这样可以加快文件的访问速度。

注:这里有两种"打开文件表"


1.系统的打开文件表(整个系统只有一张),这个表中记录了所有被进程使用的文件。


2.另外,每个进程都有自己的一张"打开文件表",这个表中记录了每个进程打开的文件。这一表中记录了系统索引号。这一索引号对应了系统"打开文件表"的编号。


•系统的打开文件表中记录了"打开计数器",记录此时有多少个进程打开了此文件。


•用户进程的打开文件表中记录了"读写指针",记录了该进程对文件的读/写操作进行到的位置。


•用户进程的打开文件表中记录了"访问权限",如果打开文件时声明的是只读”,则该进程不能对文件进行写操作。


不同进程对同一文件的读写指针(读/写进行到的位置)不同,访问权限不同。

为什么需要在系统中设置打开文件表的总表?


可以方便实现某些文件管理的功能。例如:在Windows系统中,我们尝试删除某个txt文件,如果此时该文件已被某个“记事本”进程打开,则系统会提示我们“暂时无法删除该文件”。其实系统在背后做的事就是先检查了系统打开文件表,确认此时是否有进程正在使用该文件。


读文件与打开文件的联系与区别:


联系:


都会使用到内存中的“文件打开表”,系统会将文件的索引号(这个“索引号”,也称“文件描述符”)返回给用户。之后用户使用打开文件表的索引号来指明要操作的文件,即之后用户进程再操作文件就不需要每次都重新查目录了,这样可以加快文件的访问速度。


区别:


open(打开文件)不会把文件数据直接读入内存,而是将目录项复制到内存的“打开文件表”)


read(读文件)会将文件数据从外存读入内存。


6.关闭文件(close系统调用)

6.可以“关闭”文件(读/写文件结束之后,需要“关闭文件”,即close系统调用)这和用户点击关闭按钮触发的delete系统调用不同。


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


1.将进程的打开文件表相应表项删除。


2.回收分配给该文件的内存空间等资源。


3.系统打开文件表的打开计数器count减1,若count=0,则删除对应表项。例如,在打开文件示例中的打开计数器由2变为1。

注:可用几个基本操作完成更复杂的操作,比如:“复制文件”:先创建一个新的空文件,再把源文件读入内存,再将内存中的数据写到新文件中。

六.文件的物理结构

1.对非空闲磁盘块的管理

外存与内存相同,外存也是由一个个存储单元组成的,每个存储单元可以存储一定量的数据(如 1B)。每个存储单元对应一个物理地址。


类似于内存分为一个个“内存块”,外存会分为一个个“块/磁盘块/物理块”。每个磁盘块的大小是相等的,每块一般包含2的整数幂个地址( 如本例中,一块包含 2^10 个地址,即 1KB)。


同样类似的是,在内存管理中,进程的逻辑地址空间被分为一个一个页面,在外存管理中,为了方便对文件数据的管理,文件的逻辑地址空间也被分为了一个一个的文件“块”。


于是文件的逻辑地址也可以表示为(逻辑块号,块内地址)的形式。操作系统同样需要将逻辑地址转换为外存的物理地址(物理块号,块内地址)的形式(该物理地址用户是不可知的,用户只能通过逻辑地址来操作自己的文件,操作系统要负责实现从逻辑地址到物理地址的映射)。块内地址的位数取决于磁盘块的大小。(例如这里,一块物理块包含2^10个地址,那么块内地址的位数为10位)。

注:很多操作系统中,磁盘块的大小与内存块、页面的大小相同,那么内存与磁盘之间的数据交换(即读/写操作、磁盘I/O)都是以“块”为单位进行的。即每次读入一块,或每次写出一块。

外存被分为一个个磁盘块,那么该如何存放文件数据呢?这就是我们要探讨的文件的物理结构,即文件分配方式

(1)连续分配

连续分配方式要求每个文件在磁盘上占有一组连续的块。也就是逻辑相邻的块在物理上也必须相邻。并且依然要保持块间的相对顺序。

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


逻辑地址(逻辑块号,块内地址)→物理地址(物理块号,块内地址)。只需转换块号就行,块内地址保持不变就行了。为了实现地址映射,文件目录表记录了起始块号和长度(占用多少个块),例如"aaa"文件起始块号为4,占用了连续的3个块。


用户给出要访问的逻辑块号,操作系统找到该文件对应的目录项(FCB),通过FCB就得到起始块号,用该起始块号加上逻辑块号


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


例如上图,想要访问"aaa"文件的逻辑块号2,再加上起始块号4,得到物理块号=2+4=6


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


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


顺序访问,即,想要访问"aaa"的逻辑块号2,就必须先访问逻辑块号0,1


直接访问,即,想要访问"aaa"的逻辑块号2,不需要访问0,1

连续分配支持顺序访问和直接访问(即随机访问),这是连续分配的一大优点,还有就是:

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

由于连续分配的磁盘块在物理上是相邻的,连续分配的文件在顺序读/写时速度最快。

连续分配的缺点:

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

如下图所示,黄色区域表示物理上连续分配的文件A占用了连续的三个块,橙色区域为其他文件已经占用的磁盘块,绿色区域为空闲磁盘块。


若此时文件A要拓展,需要再增加一个磁盘块(总共需要连续的4个磁盘块)。由于采用连续结构,因此文件A占用的磁盘块必须是连续的。而文件A后面相邻的块已经被其他文件占有,若要拓展文件A,那么必须把文件A迁移到有连续4个空闲磁盘块的区域中。而数据迁移需要很大开销。


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

2.物理上采用连续分配的文件存储空间利用率低


如下图所示,橙色区域为非空闲块,绿色区域为空闲磁盘块。若此时创建的新文件大小为3个块,而连续分配需要连续的3个磁盘块,那么无法为其分配足够的存储空间。


所以物理上采用连续分配,存储空间利用率低,会产生难以利用的磁盘碎片。可以用紧凑来处理碎片,但是需要耗费很大的时间代价。

(2)链接分配

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

隐式链接:

目录中记录了文件存放的起始块号和结束块号。当然,也可以增加一个字段来表示文件的长度。除了文件的最后一个磁盘块之外,每个磁盘块中都会保存指向下一个盘块的指针,这些指针对用户是透明的。

如何实现逻辑块号到物理块号?

用户给出要访问的逻辑块号i,操作系统找到该文件对应的目录项(FCB),从目录项中找到起始块号(即0号块),将0号逻辑块读入内存,只有将0号块读入内存后,才能得到0号块指向1号块的数据,由此知道1号逻辑块存放的物理块号,于是读入1号逻辑块,再找到2号逻辑块的存放位置.………..以此类推。


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


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


采用隐式链接,是否方便拓展文件?


由于文件的块可以离散存放,若此时要拓展文件,则可以随便找一个空闲磁盘块,挂到文件的磁盘块链尾,并修改文件的FCB。


例如下图,要新增8号块,那么将8号块放到磁盘块链尾。

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

总结:

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


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


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


显式链接:

把用于链接文件各物理块的指针显式地存放在一张表中。即文件分配表(FAT, File Allgcation Table)


假设某个新创建的文件“aaa”依次存放在磁盘块2-->5-->0-->1,那么在"aaa"这一文件的FCB(目录项)中,需要记录这一文件存放的起始块号,目录中只需记录文件的起始块号。

而FAT(文件分配表)中,会显式记录文件各个块的链接关系,例如0号物理块下一块为5号块,1号块下一块设置为特殊的值,例如-1,表示1号块是文件的最后一块……

假设某个新创建的文件“bbb”依次存放在磁盘块4-->23-->3

注意:一个磁盘仅设置一张FAT,每个文件都统一存放在这一个FAT表中。开机时,将FAT读入内存,并常驻内存。FAT的各个表项在物理上连续存储,且每一个表项长度相同,因此“物理块号”字段可以是隐含的。


采用显式链接,如何实现文件的逻辑块号到物理块号的转变?


用户给出要访问的逻辑块号i,操作系统找到该文件对应的目录项(FCB),从目录项中找到起始块号,若i>0,则查询内存中的文件分配表FAT往后找到i号逻辑块对应的物理块号。


例如,访问文件"aaa",0号逻辑块对应的物理块号为2号物理块,2号物理块对应的下一块是5号物理块(1号逻辑块),依次类推……


逻辑块号转换成物理块号的过程不需要读磁盘操作。


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


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


总结:


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


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


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


注:考试题目中遇到未指明隐式/显式的“链接分配”,默认指的是隐式链接的链接分配。


(3)索引分配

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


目录中需要记录文件的索引块是几号磁盘块。

假设某个新创建的文件“aaa”的数据依次存放在磁盘块2-->5-->13-->9。

7号磁盘块作为“aaa”文件的索引块,索引块中保存了索引表的内容。

如图所示,“aaa”文件的索引表存放在7号磁盘块中,而实际数据存放在2,5,13,9这些磁盘块中。


注:在显式链接的链式分配方式中,文件分配表FA 是一个磁盘对应一张。而索引分配方式中,索引表是一个文件对应一张。


可以用固定的长度表示物理块号(如:假设磁盘总容量为1TB=2^40B,磁盘块大小为1KB,则共有 2^30个磁盘块,则可用4B(4个字节,4*8的32个磁盘块)表示磁盘块号),因此,索引表中的“逻辑块号”可以是隐含的。

所以我们可以看到,索引表的表项每一行占有4个字节,所以只要知道索引表的起始位置,再根据逻辑块号,就可以知道该逻辑块号对应的物理块号的地址。

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

用户给出要访问的逻辑块号i,操作系统找到该文件对应的目录项(FCB),从中找到这一文件的索引块,再从这一索引块中读出索引表,将索引表从外存读入内存,并查找索引表即可知 i号逻辑块在外存中的存放位置。 而不需要先访问0~i-1号块。


可见,索引分配方式可以支持随机访问。


文件拓展也很容易实现(只需要给文件分配一个空闲块,并增加一个索引表项即可)


但是索引表需要占用一定的存储空间


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


如果一个文件的大小超过了256块,那么一个磁盘块是装不下文件的整张索引表的,如何解决这个问题?有三种方案①链接方案,②多层索引,③混合索引


①链接方案


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


我们为文件分配多个索引块,并且在每个索引块中分配一定空间用于指向下一个索引块, 若采用链接方式,索引表中只需要记录第一个索引块的块号即可。


如下图, 若想找到逻辑块号为256对应的物理块号,由于各个索引块中是用链接的方式连接起来,为了找到第二个索引块的块号,需要把第一个索引块读入内存,再根据第一个索引块中的指针,找到第二个索引块的块号,把第二个索引块读入内存,才能得到逻辑块号256对应的物理块号。

假设磁盘块大小为1KB、一个索引表项占4B,则一个磁盘块只能存放256个索引项。若一个文件大小为 256*256KB=65,536 KB=64MB


该文件共有 256*256个块,也就对应256*256个索引项,也就需要256个索引块来存储256个索引表,每个索引表对应256个索引项,这些索引块用链接方案连起来。


若想要访问文件的最后一个逻辑块,就必须找到最后一个索引块(第256个索引块),而各个索引块之间是用指针链接起来的,因此必须先顺序地读入前255个索引块。


这一方案显然很低效,所以提出了多层索引方案。

操作系统(13)-----文件管理3:https://developer.aliyun.com/article/1511186

目录
相关文章
|
Linux C语言
Linux操作系统实验四 文件管理(二)(下)
Linux操作系统实验四 文件管理(二)(下)
282 0
|
3月前
|
存储 自然语言处理 搜索推荐
【颠覆你的数字生活!】探索OS Copilot——那款让你瞬间变身超级用户、编程如呼吸般自然、文件管理如同魔法般的神奇操作系统辅助神器!
【8月更文挑战第8天】OS Copilot是一款新兴的操作系统辅助软件,通过智能化手段简化电脑使用,从办公到开发全面赋能。安装简易,启动即有引导教程。其智能命令建议功能,可在命令行输入时提供后续选项及其说明,特别适合Linux用户。内置代码片段生成器,根据需求或代码框架自动生成代码,大幅提升开发效率。文件管理助手支持批量操作且可预览结果,降低误操作风险。任务自动化功能便于设置重复性工作流程,如定时备份。搜索功能强大,支持自然语言查询。尽管尚有改进空间,OS Copilot已是提升生产力的得力助手。
108 5
|
2月前
|
存储 自然语言处理 搜索推荐
探索OS Copilot——那款让你瞬间变身超级用户、编程如呼吸般自然、文件管理如同魔法般的神奇操作系统辅助神器!
【9月更文挑战第4天】“OS Copilot”是一款高效的操作系统辅助软件,通过智能化手段简化电脑使用,涵盖智能命令建议、代码片段生成、文件管理及任务自动化等强大功能。其简洁的界面与友好的用户体验使其成为提升生产力的理想选择,无论是专业人士还是普通用户都能从中受益。从安装到实际应用都非常流畅,能显著提升工作效率,是优化数字生活的得力助手。
40 0
|
6月前
|
存储 算法 Unix
操作系统(13)-----文件管理3
操作系统(13)-----文件管理
129 0
操作系统(13)-----文件管理3
|
6月前
|
存储 安全 Linux
操作系统(13)-----文件管理4
操作系统(13)-----文件管理
59 0
|
6月前
|
存储 SQL 算法
操作系统(13)-----文件管理1
操作系统(13)-----文件管理
50 0
|
6月前
|
存储 算法 安全
|
6月前
|
缓存 算法 Linux
[操作系统] 文件管理
[操作系统] 文件管理
|
存储 算法 固态存储
操作系统之文件管理
文件管理初识 文件的属性 文件内部的数据如何组织起来? 文件之间应该如何组织起来? 操作系统应该向上提供哪些功能? 从上往下看,文件应该如何存放在外存? 其他需要由操作系统实现的文件管理功能 最后总结一下: 文件的逻辑结构 、 这里说一下随机访问和顺序访问: 随机访问(Random Access)是计算机存储介质的一种访问方式。它指的是存储介质可以以任意的、不连续的方式访问存储的每个地址。也就是说,随机访问允许直接访问存储介质的任意位置,不需要从开头逐个访问到需要的地址。 与随机访问相对的是顺序访问(Sequential Access),它要求从存
102 0
|
存储 安全 Unix
第七章 文件管理【操作系统】2
第七章 文件管理【操作系统】2
215 1