一.内存映射文件
内存映射文件----操作系统向上层程序员提供的功能(系统调用)。
•方便程序员访问文件数据
•方便多个进程共享同一个文件
传统的文件访问方式:
某文件需要存放到磁盘中,磁盘的存储空间以块为单位,则文件会被拆分为相应的大小相等的块,接着放入磁盘中。
若进程想要访问这一文件的数据,首先,该进程需要打开这一文件。
接着使用seek系统调用来指明需访问文件的哪部分数据,操作系统会用读写指针来记录这一位置。
接着进程会使用read系统调用来指明从这个位置往后要读入多少数据,例如读入10个字节,20个字节。
若现在进程读入的数据,在磁盘中的2号块中,那么操作系统就会将这部分数据读入内存。
当然也可以修改这一数据,如果想要这一修改被保存,则使用write系统调用,把内存中已经修改的数据写回磁盘。
总结,需要用到以下系统调用:
open 系统调用--打开文件
seek 系统调用--将读写指针移到某个位置
read 系统调用--从读写指针所指位置读入若干数据(从磁盘读入内存)
write 系统调用--将内存中的指定数据,写回磁盘(根据读写指针确定要写回什么位置)
内存映射文件:
内存映射文件与传统文件访问方式的区别:
若进程想要访问某一文件,就需要先通过open系统调用打开文件,再用mmap系统调用,让操作将文件映射到进程的虚拟地址空间中。这一系统调用会给程序员返回一个指针,这个指针指向刚才映射区域的起始地址。
接下来就可以用访问内存的方式访问文件数据了,就是可以通过操作系统返回的起始地址指针得到起始地址,再加上某地址的偏移量,访问某特定内存区域。
但这里注意,操作系统只是建立了和内存之间的映射关系,但并没有把文件数据读入内存,相当于缺页的状态。例如:
若进程想要访问的是第2块,操作系统发现这一块数据没有调入内存,那么操作系统就会自动将磁盘中的这一数据读入内存。
也就是说程序员不需要进行read系统调用,read是由操作系统自动完成的。
若进程想要关闭文件,进程可以使用close系统调用来关闭文件,当关闭文件后,操作系统会自动将被修改的数据写回磁盘。
也就是说程序员不需要用write系统调用将被修改的数据写回磁盘,这一步是操作系统自动完成的。
总结:
open 系统调用--打开文件
mmap 系统调用--将文件映射到进程的虚拟地址空间。
close 系统调用---关闭文件
与传统的文件访问方式的区别:
① 以访问内存的方式访问
② 文件数据文件数据的读入、写出由操作系统自动完成
③ 进程关闭文件时,操作系统自动将文件被修改的数据写回磁盘
内存映射文件能够使程序员更方便地使用文件数据,也可以实现文件的共享。
文件共享的实现:
对于磁盘中存放的某文件的数据,可以被进程1用系统调用的方式映射到自己的虚拟地址空间中,同理,也可以被进程2用系统调用的方式映射到自己的虚拟地址空间中。此时两个进程的虚拟地址空间是相互独立的。
操作系统会把这两个独立的虚拟地址空间映射到相同的物理内存中,实际操作就是,操作系统只需要修改两进程的页表,让对应的页面映射到相同的物理页框中。这样就能实现两个进程共享同一个文件的数据。
若进程1改变了2号块的数据,那么进程2会通过映射的物理内存,看到2号块数据的改变,所以
多个进程可以映射同一个文件,实现共享
在物理内存中,一个文件对应同一份数据,当一个进程修改文件数据时,另一个进程可以立马“看到”
内存映射文件的优点:
1.程序员编程更简单,已建立映射的文件,只需按访问内存的方式读写即可
2.文件数据的读入/写出完全由操作系统负责,I/O效率可以由操作系统负责优化
二.文件的属性
1.文件名
由创建文件的用户决定文件名,主要是为了方便用户找到文件,同一目录下不允许有重名文件。
2.标识符
一个系统内的各文件标识符唯一,对用户来说毫无可读性因此标识符只是操作系统用于区分各个文件的一种内部名称。
3.类型
指明文件的类型。
4.位置
文件存放的路径(让用户使用)、在外存中的地址(操作系统使用,对用户不可见)
5.大小
指明文件大小
6.创建时间、上次修改时间、文件所有者信息
7.保护信息
对文件进行保护的访问控制信息
三.文件的逻辑结构
文件的“逻辑结构”,就是指在用户看来,文件内部的数据应该是如何组织起来的。而物理结构”指的是在操作系统看来,文件的数据是如何存放在外存中的(这个下面会探讨)。
类似于数据结构的“逻辑结构”和“物理结构”。
如“线性表”就是一种逻辑结构,在用户角度看来,线性表就是一组有先后关系的元素序列,如:a,b,c, d,e 。
“线性表”这种逻辑结构可以用不同的物理结构实现,如:顺序表/链表。顺序表的各个元素在逻辑上相邻,在物理上也相邻;而链表的各个元素在物理上可以是不相邻的。因此,顺序表可以实现“随机访问”,而“链表”无法实现随机访问。
可见,算法的具体实现与逻辑结构、物理结构都有关(文件也一样,文件操作的具体实现与文件的逻辑结构、物理结构都有关)。
文件的逻辑结构如下:
1.无结构文件
由一些二进制或字符流组成,又称为“流式文件”。例如,windows操作系统中的文本文件(txt)。
2.有结构文件
由一组相似的记录组成,又称“记录式文件”。每条记录又若干个数据项组成,数据项是文件系统中最基本的数据单位。。如:数据库表文件。一般来说,每条记录有一个数据项可作为关键字(作为识别不同记录的ID)
在本例中,数据表的每一行就是一条记录,记录的是一组相关数据项的集合。学号”即可作为各个记录的关键字。
根据各条记录的长度(占用的存储空间)是否相等,又可分为定长记录和可变长记录两种。
定长记录:
这个有结构文件由定长记录组成,每条记录的长度都相同(共128 B)。各数据项都处在记录中相同的位置,具有相同的顺序和长度(前32B一定是学号,之后32B一定是姓名)
可变长记录:
这个有结构文件由可变长记录组成,由于各个学生的特长存在很大区别,因此“特长”这个数据项的长度不确定,这就导致了各条记录的长度也不确定。当然,没有特长的学生甚至可以去掉“特长”数据项。
那么有结构文件中的各记录又该如何组织起来呢?
顺序文件:
文件中的记录一个接一个地顺序排列(逻辑上),记录可以是定长的或可变长的。各个记录在物理上可以顺序存储或链式存储。
顺序存储---逻辑上相邻的记录在物理上也相邻(类似于顺序表)
链式存储---逻辑上相邻的记录物理上不一定相邻(类似于链表)
根据记录是否按照关键字的顺序进行排列,又可分为串结构和顺序结构:
串结构:指的是记录之间的顺序与关键字无关
顺序结构:指的是记录之间的顺序按关键字顺序排列
假设顺序文件在物理上采用链式存储的方式:
无论是定长/可变长记录,都无法实现随机存取,每次只能从第一个记录开始依次往后查找(因为各个元素之间存放的位置是离散的,没有规律,所以不能通过计算得到某元素的存放位置)
假设顺序文件在物理上采用顺序存储的方式:
1.若该文件是可变长记录的文件:
无法实现随机存取。每次只能从第一个记录开始依次往后查找。
由于记录内容不同,所以记录长度不同,需要显式地给出记录长度,假设用1字节表示记录长度,这些记录也是不规律的,因此如果想要找到某一条记录对应的地址,那么就需要从第一个记录依次往后查找。
所以若是可变长记录的文件,即使采用顺序存储,也无法实现顺序存储。
2.若采用定长记录:
可实现随机存取。记录长度为L,则第i个记录存放的相对位置是i*L
(1)若记录采用串结构,即记录之间的顺序与关键字无关,那么无法快速找到某关键字对应的记录,所以只能从头开始寻找指定关键字对应的记录
(2)若记录采用顺序结构,即记录之间的顺序按关键字顺序排列,那么可以快速找到某关键字对应的记录(如折半查找)。
所以:定长记录的顺序文件,若物理上采用顺序存储,则可实现随机存取;若能再保证记录的顺序结构,则可实现快速检索即根据关键字快速找到对应记录)
注:一般来说,考试题目中所说的“顺序文件”指的是物理上顺序存储的顺序文件。顺序文件的缺点是增加/删除一个记录比较困难(如果是串结构则相对简单,因为串结构不需要保证记录按照关键字排序)。
实际上,为了减少磁盘的I/O次数,操作系统会管理一个日志文件,用日志文件记录对文件记录进行修改的信息,隔一段时间后再将这些信息统一地合并到外存的文件数据中。
总结:
索引文件:
对于可变长记录文件,要找到第i个记录,必须先顺序第查找前i-1个记录,但是很多应用场景中又必须使用可变长记录。所以要使用到索引文件。
索引文件结构如下,每一个文件会记录一张索引表以加快检索速度,每个索引表项会对应文件的一条记录,文件中的这些记录在物理上可以离散地存放。但索引表的各个表项是需要连续存放的。另外,每个索引表的表项大小相同。
索引表本身是定长记录的顺序文件。因此可以快速找到第i个记录对应的索引项。可将关键字作为索引号内容,若按关键字顺序排列,则索引表还可以支持按照关键字折半查找。
每当要增加/删除一个记录时,需要对索引表进行修改。由于索引文件有很快的检索速度,因此主要用于对信息处理的及时性要求比较高的场合。
另外,可以用不同的数据项建立条个索引表。如:学生信息表中,可用关键字“学号”建立一张索引表。也可用“姓名”建立一张索引表。这样就可以根据“姓名”快速地检索文件了。(例如:SQL就支持根据某个数据项建立索引的功能)
索引顺序文件:
对于索引文件,每个记录对应一个索引表项:因此索引表可能会很大。比如:文件的每个记录平均只占8B,而每个索引表项占32个字节,那么索引表都要比文件内容本身大4倍,这样对存储空间的利用率就太低了。所以引出了索引顺序文件。
索引顺序文件是索引文件和顺序文件思想的结合。索引顺序文件中,同样会为文件建立一张索引表,但不同的是:并不是每个记录对应一个索引表项,而是一组记录对应一个索引表项。
在下面例子中,学生记录按照学生姓名的开头字母进行分组。每个分组就是一个顺序文件,分组内的记录不需要按关键字排序
操作系统(13)-----文件管理2:https://developer.aliyun.com/article/1511180