说明:该系类文章更多的是从从哲学视角看 操作系统 这门学科。同时也是 操作系统的学习笔记总结。因为博主 这些年主要是以研究安卓系统和 嵌入式Linux为主,因此这个系类文章也是这两个领域不可或缺的基石之一,尤其是对操作系统感兴趣的伙伴可特别关注。
16 文件系统
16.1 为什么需要文件系统
将数据存储在内存上,掉电后数据就会丢失,要想把数据保存下来,就需要将数据放在一种持久的媒介上,就是磁盘。磁盘的特点是容量大、低成本、持久、可共享。即使掉电依然不会丢失数据。驱动磁盘对于一般用户而言非常困难,因此需要操作系统来进行抽象,而操作系统将磁盘其抽象为文件与文件系统。
16.2 文件系统
文件系统就是操作系统提供的一种抽象。具体描述如下:文件系统将具体的磁盘物理特性转换为用户能够看到的路径名和文件名,即用户只要给出路径名、文件名即可,不需要知道磁柱、磁道、扇面和数据块等信息。文件系统主要就是存储大量信息,多个进程可以访问同一个文件,进程结束也不会影响文件的持续存在。
16.3 文件系统的目标
文件系统的目标:地址保护和地址独立。
- 地址保护:对文件的访问进行限制。
- 地址独立:文件数据的产生于文件将来存放的位置地址相互独立。
16.4 文件的基本知识
下面内容是从用户的角度看待文件以及文件系统的,从用户的角度分析文件的地址独立和地址保护是怎样实现的。
16.5 从用户角度看文件系统
- 对于用户而言,他们关心怎样用。
- 对于设计人员而言,他们关心怎样实现。
16.5.1 文件命名
一个符号名,便于访问一个文件的访问;具体来说就是找到文件存放在磁盘上的所有数据块。
操作系统如何找到这些数据块:
- 将该文件名翻译成其数据块在磁盘上存放的地址。(由于磁盘的寻址单位是扇面,这些磁盘地址实际上就是一个个的扇面号。由于一个文件可能占用多个扇面,文件在磁盘上的地址通常有多个)
- 根据文件在磁盘上的组织方式不同,这种从名字到磁盘地址的翻译将有所不同。
16.5.2 扩展名
扩展名用于表明文件的类型,入二进制文件、文本文件等。
注意:扩展名对文件类别的指示仅仅是指示性的,并不具有强制性。(在UNIX下,系统并不遵守扩展名;而在windows下,扩展名规则是被遵守的,例如可执行文件只有.bat、.exe和.com)
16.5.3 内容寻址
提供文件的内容,以供操作系统来查找,数据库就是以这种方式来查找的,这种方式成为内容寻址。
16.5.4 文件内容组织
从哲学角度来看,文件组织的形式有两种:关系导向图组织和非关系导向图组织。
@1 关系导向图组织:将数据之间的关系记录在文件里面,文件的构造和数据之间的关系存在某种对应关系。
- 记录流存放方式:数据以一个记录一个记录的方式顺序排列,并不捕捉每个记录之间的关系。
- 树形结构存放方式:数据不只是按照记录存放,且捕捉记录之间的关系,但是记录之间的关系是一种层次结构,不形成环。
- 网络存放方式:记录之间的关系可以形成环。
三种结构比较如下:
@2非关系导向图组织:不考虑数据里面的任何结构,对于此种方法,数据就是数据流,没有记录,没有关系;这个数据可以是字节流,可以是数据块流,不同之处就是这个“流”的单位不同,如图所示:
对于如此多的组织方式中,哪一种最有效需要分析,分析过程如下:
- 记录:数据最小的构成单位,每次读取一个/多个记录,不能再记录中间开始读写操作,因此构建文件系统需要知道很多信息。(文件系统设计费时费力)
- 树形/网络型:文件系统需要知道的信息更多了。(文件系统设计费时费力)
- 非关系导向性组织方式:这种模式下无需知道关于数据的任何信息,这种方式下,文件不必知道数据是什么,这种方式下文件系统将大大简化。(相对来讲简单得多)
对于文件系统,需要做的是让磁盘更加容易使用,而不是涉及文件里面数据的语义。因此从可靠性、安全性、兼容性来讲,关系导向图方式都不合适。对于非关系导向图而言 字节流方式最受欢迎。因为从计算机来看,大部分寻址的最小单位是字节,因此,字节是最为简单的了。总体来讲,字节流文件系统的好处是:操作系统代码更加可靠、更加灵活、用户编写程序也更加方便。
16.5.5 文件类型
大部分操作系统支持多种文件。根据文件的内容是用户数据还是文件系统本身的数据,文件分为3种:目录、一般文件、块文件
- 目录:记录文件的文件,即它的内容是关于别的文件。
- 一般文件:用来保存数据。对于一般文件来说,根据其内容的组织方式不同,可以分为下列几种文件:
- 文本文件:存放的是没有经过处理的数据,即以ASCII码表示的数据。任何编辑器都可以打开这种文件。
- 二进制文件:经过编码的文件,普通编辑器打不开,必须用专门的应用软件才能打开。另外,加密文件也是二进制文件。
- 块文件是关于输人输出设备的:块文件模拟的是I/O或者为I/O提供的一个抽象,对于每个输入输出设备,我们以一个文件来表示。需要与该设备发生数据交换时就以该文件来替代。通过块文件,输入输出和文件系统就统一了。(文件系统其实就是为磁盘提供一个抽象。而磁盘可以看作是输入输出设备)
16.5.6 文件格式
不同类型的文件有着不同类型的逻辑单元,而这些逻辑单元在空间上的关系也因文件系统的不同和操作系统的不同而不同。其中,可执行文件和归档文件在UNIX下的格式如图所示:
对于可执行文件来说,它有一个标题(header)、一个代码部分、一个数据部分、一个重定位部分、一个符号表
而标题通常分为多个逻辑单元:魔数(告诉操作系统这个文件的类型。魔数是个很重要的数字,如果你把一个不是可执行的文件的魔数改成可执行文件的魔数,将会产生不可预料的后果。当然,不同的文件类型也可能共享同一种文件格式。(例如,windows里而的pE格式就是对象文件(ohj文件)、可执行文件、动态链接库、驱动程序等共用的一种格式))、代码尺寸、数据尺寸、共享空间尺寸、符号表尺寸、程序入点和各种标志位。
16.5.7 文件访问
文件的访问类型只有两种:顺序访问和随机访问。
- 顺序访问:从开头访问起,按先来后到的顺序读取数据。不能在中间随便跳转,但可以进行快进或者快退。显然,顺序访问的缺点很多。你不能想访问哪就访问哪
- 随机访问:可以按照任意顺序读取数据记录。我们先对文件进行选点(seek),到达指定的位置后再开始读写。读写一段数据后又可以再次选择新的位置。这种随机读写是数据库能够工作的基础(现代的操作系统无一例外都提供随机访问,这是因为我们的存储媒介已经是随机读写的磁盘了)。
16.5.8 文件属性
对于不同的操作系统,文件的属性、种类和数量可以不同。但是每一种属性都有自己的用途常见的文件属性如图所示:
大部分语义直接明了,只有部分需要解释:
- 临时文件标志:用来指示该文件为临时创建的用来存放中间结果的,在创建该文件的进程结束后.该文件将被删除。
- 锁标志:指示该文件是否已经上锁;为l时表明该文件当前被某个进程锁住,其他进程将不能打开该文件。利用对文件上锁,两个进程可以进行同步。
- 记录长度、关键字位置、关键字长度几个属性针对的是记录流文件:对于字节流文件组织方式来说,这些属性是没有的。
- 最后修改时间、最后访问时间等属性经常由备份软件用来判断是否是差分增量。
文件的属性可以被修改。而修改的方式有两种:一是直接在shell下用工具程序(utilities)来进行修改;二是在程序中使用系统调用(systemcall)来进行修改。
16.5.9 文件操作
可以对文件进行的操作有:创建/删除、打开/关闭、读写添加、寻找访问位置、读取属性/设置属性、重命名等
16.6 地址独立的实现机制:文件夹
- 文件夹也称为目录(folder),它保存的是关于文件及文件系统的信息:即文件夹就是用来跟踪文件,里面存放的是从文件到文件在磁盘的地址的映射。文件夹对于文件来说,就相当于动态地址翻译对于虚拟地址的作用,即从虚拟地址到实际地址的一种翻译机制。
- 文件夹需要的是提供一种找出个文件所有磁盘块的方法。
- 文件夹本身也是文件。可以像对待文件时对待文件夹;使用同样的存储结构来存放文件夹的数据;文件夹里面的每个记录本身又可以是文件夹。
16.6.1 文件夹结构
文件夹的层次结构如下:
根目录是一个文件系统的总起点,它在操作系统启动的时候加载到内存。从根目录开始,该文件系统里的所有文件都可以找出来。由于根目录是整个文件系统的源点,如果根目录损坏,则整个文件系统都无法访问,也就说文件系统已经崩溃(当然,我们可以通过文件恢复和修复等手段来获得对部分文件的访问能力,但这不是操作系统要探讨的问题)。
16.6.2 相对路径和绝对路径
- 相对路径:往往不以/开头的路径名,从当前所处的目录角度来看某一个文件的访问路径。
- 绝对路径:往往以/开头的路径名,即从根目录的视角来看某一个文件的访问路径。
注意:相对路径与绝对路径相比,并不都是节省访问次数,即各有各的优势与缺陷。
16.6.3 共享与链接
链接:使文件的访问和文件的共享变得方便,而且实现的是即时共享(访问的就是你想要的文件,不是副本)
16.7 文件系统调用
从用户角度看,操作系统提供的文件系统界而就是文件系统调用。用户可以在程序中通过这些系统调用对文件系统进行读写操作。这些系统调用包括打开文件、关闭文件、读文件内容、写文件内容等。下面是一个例子,使用文件系统调用实现文件复制的简单程序,如图所示:
工作原理如下:
- 打开源文件和目标文件;
- 然后循环往复地将源文件的内容读到一个缓冲区;
- 将缓冲区的内容写到输出目标文件里。
- 当复制结束后,关闭源文件和目标文件。
那么上述程序有一个问题,正确性方面是没有问题,但在效率上却不太令人满意。这是因为该程序的系统调用次数太多,而系统调用需要陷人到内核。另外,每次系统调用都需要进行磁盘操作,而磁盘操作的效率远远低于内存操作的效率。解决这个问题可以将缓冲区设大,这样可以降低系统调用和磁盘访问的次数。但缓冲区越大,需要的内存就越大,将造成程序的可执行性下降。而且,就算缓冲区很大,文件还可以更大,还是不能从根本上解决效率低的问题。那么解决这个问题需要新的策略:内存映射的文件访问。
16.8 内存映射的文件访问
解决读写文件效率低下的中心思想就是把磁盘访问变成内存访问。实现这种访问转变的手段就是内存映射的文件访问。
- 内存映射的文件访问原理:把需要访问的文件映射到一个进程的虚拟地址内。这样,访问该虚拟地址就相当于访问文件。这样文件访问就变成内存访问。这样,磁盘访问变成了内存访问,效率自然提高。
- 内存映射的文件访问是为了文件的共享。具体来说,我们可以将同一个文件映射到两个或多个进程的虚拟地址空间。这样每个进程对相应的虚拟地址空间进行访问时就是对同一个文件进行访问。