所有的计算机应用程序都需要存储和检索信息。进程运行时,可以在它自己的地址空间存储一定量的信息,但存储容量受虚拟地址空间大小的限制。第二个问题:进程终止时,它保存的信息也随之丢失。对于很多应用而言,有关信息必须能保存几星期、几个月,甚至永久保留。第三个问题是:经常需要多个进程同时存取同一信息。因此,长期存储信息有三个基本要求:
1)能够存储大量信息。
2)使用信息的进程终止时,信息仍旧存在。
3)必须能使多个进程并发存取有关信息。
我们用了一个新的抽象-----------文件来解决这个问题。进程(或线程)、地址空间和文件,这些抽象的概念均是操作系统中最重要的概念。文件时进程创建的信息逻辑单元。操作系统中处理文件的部分称为文件系统,首先从用户角度来考察文件。也许任何一种抽象机制的最重要的特征就是对管理对象的命名方式,需要操作系统用圆点隔开分为两个部分,圆点后面的部分称为文件扩展名。文件可以有多种构造方式,常见的是三种方式:字节序列、记录序列、树。把文件看成字节序列为操作系统提供了最大的灵活性。所有的UNIX、MS-DOS以及Windows都采用了这个方式。第二个模型中,文件时具有固定长度记录的序列,每个记录都有其内部结构。第三者模型中,由一棵记录树构成,每个记录并不具有同样的长度,而记录的固定位置上有一个“键”字段。另外很多操作系统支持多种文件类型。如UNIX和Windows中都有普通文件和目录,UNIX还有字符特殊文件、块特殊文件。普通文件中包含有用户信息。目录是管理文件系统结构的系统文件。普通文件一般分为ASCII文件和二进制文件。ASCII文件最大优势是可以显示和打印,还可以用任何文本编辑器进行编辑。而二进制文件打印出来是无法理解的,通常二进制文件有一定的内部结构,使用该文件的程序才了解这种结构。二进制文件一般形式是一个可执行文件,一个存档文件,前者文件头以所谓的魔数开始,后者以模块头开始。关于文件的存取,一般分为顺序存取、随机存取。前者比较适合存储介质是磁带,后者比较适合磁盘,而且对应用程序而言是必不可少的,如数据库系统。关于文件属性,因为文件除了文件名和数据。另外,所有的操作系统还要保存相关信息,如创建时间、文件大小等。这些附加信息称为文件属性(也称为元数据)。关于文件的操作很简单,这里就不要总结了。
文件系统通常提供目录或文件夹用于记录文件。目录系统最简单形式是在一个目录中包含所有的文件,这时称为根目录(也就是一级目录系统)。另外需要层次结构的目录,可以进行文件分类。绝对路径它是由根目录到文件的路径组成。相对路径名,它常和工作目录一起使用。
文件系统的实现
磁盘的0号扇区称为主引导记录(MBR),用来引导计算机。在MBR的结尾时分区表。该表给出了每个分区的起始和结束地址。表中的一个分区被标记为活动分区。在计算机被引导时,BIOS读入并执行MBR。MBR做的第一件事是确定活动分区,读入它的第一个块,称为引导块,并执行之。引导块中的程序将装载该分区中的操作系统。
除了从引导块开始之外,磁盘分区的布局是随着文件系统的不同而变化的。格式如下:
引导块 |
超级块 |
空闲空间管理 |
i节点 |
根目录 |
文件和目录 |
文件的存储,不同的操作系统采用了不同的方法。
第一是连续分配,连续磁盘空间分配方案有两个优势,首先是实现简单,其次就是读操作性能较好。其缺点是随着时间的推移,磁盘会变得零碎。开始时,碎片并不是问题,因为每个新的文件都在先前文件的磁盘结尾写入。但是,磁盘最终会被充满,所以要么压缩磁盘,要么重新使用空洞中的空闲空间。前者由于代价太高而不可行;后者需要维护一个空洞列表,这是可行的。但是,当创建一个新文件时,为了挑选适合大小的空洞存入文件,就有必要知道该文件的最终大小。然而连续的分配方案在CD-ROM上被广泛使用着,在这里所有的文件大小都事先知道。DVD的情况有些复杂,因为采用的是UDF格式,使用了一个30位的数来代表文件长度,从而把文件大小限制在1GB。
第二链表分配,为每个文件构造磁盘块链表,每个块的第一个字作为指向下一块的指针,块的其他部分存放数据。该方案不会因为磁盘碎片而浪费存储空间。尽管顺序读文件非常方便,但是随机存取却相当缓慢,因为每次都必须从头开始,显然,读操作太慢了。另外由于指针占去了一些字节,每个磁盘块存储数据的字节数不再是2的整数次幂。
第三在内存中采用表的链表分配,如果取出每个磁盘块的指针字,把它放在内存的一个表中,就可以解决上述链表的两个不足。内存中的这样一个表格称为文件分配表(FAT)。这种方式,随机存取很方便。主要缺点是必须把整个表都存放在内存中。对于200GB的磁盘和1KB大小的块,这张表需要2亿项,每一项对应于这2亿个磁盘块中的一个块。那么要占用到600MB或800MB的内存,不太实用。很显然FAT方案不适合大磁盘。
第四i节点,最后一个记录各个文件分别包含哪些磁盘块的方法是给每个文件赋予一个称为i节点的数据结构,其中列出了文件属性和文件块的磁盘地址。该机制最大优势占用内存空间少,因为链接表的大小与磁盘文件的大小无关。但是有一个问题就是如果每个i节点只能存储固定数量的磁盘地址,那么当一个文件所含的磁盘块的数目超出了i节点所能容纳的数目怎么办?
目录实现
在读文件前,必须先打开文件。打开文件时,操作系统利用用户给出的路径名找到相应目录项。那么目录系统的主要功能是把ASCII文件名映射成定位文件数据所需要的信息。简单的设计就是简单目录,包含固定大小的目录项,在目录项中有磁盘地址和属性;另外就是每个目录项只引用i节点的目录。还有就是给予文件名一个长度限制,典型值为255个字符。这种处理很简单,但是浪费了大量的目录空间。一种替代方案是放弃“所有目录项大小一样”的想法。就是每个目录项有一个固定部分,这个固定部分通常以目录项的长度开始,后面是固定格式的数据。一般采用两种方式:a)在行中;b)在堆中。
共享文件
当几个用户同在一个项目里工作时,他们常常需要共享文件。但是共享文件时方便,但也带来些问题,如果目录中包含磁盘地址,则连接文件时,必须把磁盘地址也要复制过来。这样当一个用户修改了文件,另一个用户是不知道的,所以违背了共享的目的。解决这一问题,有两种方式,一种是磁盘块不列入目录,而是列入一个与文件本身有关联的小型数据结构中。第二种方式就是采用LINK的方式。
日志结构文件系统
不断进步的科技给现有的文件系统带来了更多的挑战,特别是CPU的运行速度越来越快,磁盘容量越来越大,价格也越来越便宜,同时内存容量也以指数形式增长。而没有得到快速发展的参数是磁盘的寻道时间。所以这些问题综合起来,便成为影响很多文件系统性能的一个瓶颈。由此就诞生了日志结构文件系统(LFS)。
促使设计LFS的主要原因是,CPU的运行速度越来越快,RAM的内存容量变得更大,同时磁盘高速缓存也迅速增加。进而,不需要磁盘访问操作,就有可能满足直接来自文件系统高速缓存的很大一部分读请求。未来多数的磁盘访问是写操作。而且大多数文件系统中,写操作往往都是零碎的。出于这一原因,LFS的设计者决定重新实现一种UNIX文件系统,该系统即使对于一个大部分由零碎的随机写操作组成的任务,同样能够充分利用磁盘的带宽。其基本思想是将整个磁盘结构化为一个日志。每隔一段时间,或是有特殊需要时,被缓冲在内存中的所有未决的写操作都被放到一个单独的段中,作为在日志末尾的一个邻接段写入磁盘。
日志文件系统
虽然基于日志结构的文件系统是一个很吸引人的想法,但是由于它们和现有的文件系统不相匹配,所以还没有被广泛应用。尽管如此,它们内在的一个思想,即面对出错的鲁棒性,却可以被其他文件系统所借鉴。这里的基本想法是保存一个用于记录系统下一步将要做什么的日志。
虚拟文件系统
即使在同一台计算机上同一个操作系统下,也会使用很多不同的系统。一个windows可能有一个主要的NTFS文件系统,但是也继承的FAT-32或者FAT-16驱动。由于多种文件系统的存在,所有需要使用虚拟文件系统概念尝试将多种文件系统统一成一个有序的框架。关键的思想就是抽象出所有文件系统都共有的部分,并且将这部分代码放在单独的一层,该层调用底层的实际文件系统来具体管理数据。