第一节 文件管理的基本概念

对信息存储的基本要求:

  • 能够存储大量的信息
  • 长期保存信息
  • 可以共享信息

文件是通过OS来管理的,管理的内容包括文件的组织结构、命名、存取、使用、保护和实现方法。

OS为系统管理者和用户提供了对文件的透明存取,即不必了解文件存放的物理机制和查找方法,只需要给定一个代表某段程序或数据的文件名称,文件系统就会自动地完成对该文件(与文件名称对应的文件)的指定操作。

一、文件管理任务

从研究角度分:

  • 用户角度:关心文件的组成、命名、保护以及可以进行哪些操作等。
  • OS角度:关心目录如何实现、怎样管理存储空间、文件存储位置、磁盘实际运作方式、存取速度、磁盘利用率等。
1、文件的定义

一组带标识的,在逻辑上有完整意义的信息项的序列;标识指文件名,信息项构成文件的内容。

信息项时构成文件内容的基本单位,它时有序的序列。

2、文件系统

是OS的一种统一管理信息资源的软件;提供文件的存储、检索、更新、共享、保护并方便用户使用。

二、文件的存储介质即存取方式

1、外存储设备的特点

容量大、非易失、熟读慢、成本较低。

组成结构:

  • 驱动部分(驱动器):使计算机能实现读写存取在介质上的内容。
  • 存储介质(卷):信息容器。
2、外存储设备的存储介质

(1)磁带:最早的存储介质

是顺序存取设备;容量大,速度慢,只能顺序存取不适用于随机存取;常用于后备存储和保存不经常使用的信息。

(2)磁盘

分为软盘和硬盘;软盘容量小,易磨损,保存不变已被淘汰;现在流行的磁盘通常就是指硬盘,它容量大,成本低,是典型的随机存取设备,可直接存取其上任意物理块,可以将磁头直接移动到所要求的位置上。

一次访问磁盘的时间计算:

【操作系统】第六章 文件系统_存储空间

其中,寻道是机械动作,耗时最长。

硬盘的物理地址:由柱面号(磁道号)、扇区号、磁头号(盘面号)组成。

(3)光盘

(4)闪存

非易失、电可擦除、可随机存取、无机械部件;寿命和可靠性高;读写比磁盘更快且方便。

3、文件在存储设备中的存取方式

用户要求:

  • 方便:不涉及硬件细节,直接使用逻辑地址和逻辑动作。
  • 高效:速度快、容量大且利用率高。
  • 安全:安全可靠,防止硬件故障的破坏。
  • 方便共享:可动态扩大、缩小,携带于拆卸方便。
  • 以尽可能小的代价实现。

文件存取方式:

  • 一种逻辑结构和物理结构之间的映射机制;
  • 方法有顺序和随机两种。

(1)顺序存取:流式文件

(2)随机存取:又叫直接存取;用户按任意次序直接存取文件中的任一记录。

UNIX类OS两者都采用了。

三、文件的分类

1、按用途分类
  • 系统文件
  • 库函数文件
  • 用户文件
2、按文件组织形式
  • 普通文件
  • 目录文件
  • 特殊文件:以文件形式存在和访问的设备
3、其他一些常见的文件分类方式
  • 按保护方式:只读、读写、可执行...
  • 按信息流:输入文件、输出文件
  • 按存放时限:临时、永久、档案
  • 按使用介质:磁带、磁盘、卡片、打印
  • 按组织结构:
  • 用户视角:流式、记录式
  • 介质视角:顺序、链接、索引
4、UNIX类OS中的文件分类
  • 普通文件:内部无结构,由一串平滑字符串组成。
  • 目录文件:由文件目录项构成。
  • 特殊文件:I/O设备。

第二节 文件的逻辑结构和物理结构

任何一种文件都有其内在的文件结构,被称为物理结构,它是文件在实际存储空间在存储时的结构。

用户看到的是经过抽象的文件结构,这就是文件的逻辑结构。

一、文件的逻辑结构

OS在设计文件逻辑结构时遵循的原则:

  • 易于操作:方便、易学、易用
  • 查找容易
  • 修改方便
  • 空间紧凑:若对文件的基本信息单位操作不多,则适合采用字符流的无结构方式。(比如:可执行文件、目标文件代码文件等)

文件的逻辑结构分类:

1.无结构的字符流文件:

-   有序的字符(字符是其基本单位,通常一个字符占用1个字节)集合,长度是所包含的字符个数。
-   一串有开头和结尾的连续字符。
  • 1.
  • 2.

【操作系统】第六章 文件系统_夏明亮_02

2.有结构的定长记录文件

  • 定长:各记录长度相等。
  • 记录式:将文件中的记录按各种不同方式排列。

【操作系统】第六章 文件系统_文件系统_03

3.不定长记录文件构成的记录树

  • 不定长:各记录长度不相等。
  • 记录式:将文件中的记录按各种不同方式排列。

记录由在文件中的逻辑地址(相对位置)与记录名所对应的一组键、属性及其属性值所组成。

记录文件:一组有序记录的集合,记录使其基本单位。

二、文件的物理结构

如何在物理存储器上存储文件:

  • 顺序结构
  • 链接结构
  • 索引结构

1、顺序结构(连续结构)

逻辑上连续的文件信息依次存放在连续的物理块中。

优点:仅知道起始块号和文件长度即可存取文件;支持顺序和随机存取。

缺点:文件不能(很难)动态增长(要求物理块必须连续);且易产生碎片;解决的办法是采用离散(非连续)存储块分配方式。(链接和索引)

2、链接结构

为每个文件构造所用的磁盘块链表,且每个物理块中设一个指针,指向其后续的物理块。

优点:解决了碎片问题,无需连续的存储空间,空间利用率高;文件可动态扩充;插入、删除方便。

缺点:存取速度慢,不适用于随机存取,磁头移动多,效率低;需要额外的存储指针的空间;可靠性可能因指针出错而降低。(可采用双向链接或在每个物理块中存储文件名和相对应的块号等办法优化,但是只能有限地解决。)

典型的链接结构式FAT系统

3、索引结构

原理:将每个物理块的指针字符集中存放在称为索引表的数据结构中。在每个文件相应的目录条目中包括文件的索引表地址,索引表中的第i个条目指向文件的第i块。

优点:保持了链接结构的优点,又解决了其缺点;即适合顺序存取又适合随机存取。(因为:逻辑块号和物理块号全部存储在索引表中而不是分散在各物理块中。)

缺点:会引起较多的寻道次数和寻道时间,索引表本身需增加空间开销;若文件很大,索引表也会很大,若索引表大小超过一个物理块,那么需要考虑索引表的物理存放结构:

  • 若采用顺序结构则不利于动态增加
  • 若采用链接结构则增加访问的时间开销
  • 较好的方案是采用间接索引(也叫多级索引),但这会降低文件的存取速度;大多数文件是不需要的。

三、UNIX的三级索引结构

UNIX OS的i节点(inode)是一种多级索引文件结构。它在索引结构基础上进行了结构上的变化,克服了索引结构的缺点;掌握i节点就掌握了多级索引文件结构的工作原理。

基本思想:每个文件赋予一张称为i节点的小表,其中列出了文件属性和文件中各数据块在磁盘上的地址。

【操作系统】第六章 文件系统_文件系统_04

UNIX和类UNIX操作系统(如Linux)中的i节点(inode),它是文件系统中的重要概念,用于存储文件的元数据信息。 每个文件或目录在文件系统中都有一个唯一的i节点。

i节点包含哪些信息?

  • 文件类型:如普通文件、目录、符号链接等。
  • 权限和所有者:包括文件的权限模式(如读、写、执行权限)和所有者(用户和组)。
  • 文件大小:文件实际占用的大小。
  • 时间戳:包括文件的创建时间、修改时间和访问时间。
  • 指向数据块的指针:对于较小的文件,i节点直接包含文件数据块的地址;
  • 指向间接索引表指针:对于较大的文件,i节点包含指向间接索引表的间接指针。
  • 链接计数:指向该i节点的硬链接数量。当链接计数为零时,文件系统可以回收这个i节点和文件数据块。
  • 其它元数据:如文件系统标识、文件版本号等。

第三节 文件目录

文件目录是文件系统的重要组成部分,负责组织和管理文件。

文件目录提供了文件的层次结构文件属性以及文件访问路径的信息。

一、文件控制块

文件系统的一个特点是"按名存取";其中,名是文件的符号名(它与文件具体的物理路径对应)。

OS为每个文件都设置一个描述性数据结构:文件控制块(FCB);将所有文件的FCB有机地组织起来构成FCB的集合,称之为目录。

目录实际上是文件符号名到文件物理地址的一种映射机制。

FCB是文件存在的标志,它记录了系统管理文件所需的全部信息,通常应包含:

  • 文件名:用户给文件取得符号名。
  • 文件号:系统在文件创建时指定的一个编号;它唯一地标识一个文件,因此,同一系统中不能重复。
  • 用户名:文件的创建者。
  • 文件物理地址:
  • 若采用链接结构,则此处记录首指针。
  • 若采用索引结构,则此处记录该文件索引表地址。
  • 文件长度与记录大小:文件的长度和每个物理块的大小。
  • 文件类型:只读、可执行、可读写。
  • 共享说明:是否允许其他用户使用(同组、同系统...).
  • 文件逻辑结构:流式/记录式。
  • 文件物理结构:顺序结构/链接结构/索引结构。
  • 口令:访问密码。
  • 保存期限:预计该文件的保存时间(临时、一次性、长期存储...)。

二、文件目录和当前目录

1、目录结构

(1)一级目录结构:最简单,最原始。

在系统中设置一张线性目录表,表中包括所有文件的FCB,每个FCB指向一个普通文件。创建文件时先从该表中申请一项;删除文件时也从该表删除对应的项。

特点:易实现,各文件项都是平等的地位,只能按顺序/连续结构存放,文件必须与文件一一对应,不能重名;检索时效率低,平均时长长。

(2)二级目录结构

目录被分为两级:

第一级为主文件目录(MFD),给出了用户名和用户文件目录所在物理位置;

第二级为用户文件目录(UFD),又称用户子目录,它给出了该用户所在文件的FCB。

特点:解决了重名问题,可实现用户间的共享,查找时间也变短;但是增加了系统开销。

(3)多级目录结构

将二级目录层次结构加以推广,又称为树形目录结构;它便于文件分类,主要特点有:

  • 层次清晰
  • 解决了文件重名问题
  • 查找的速度快(可只查子集)

目前大多数OS:UNIX、Linux、Windows等都采用多级目录结构。

【操作系统】第六章 文件系统_夏明亮_05

多级目录结构形成一棵树,每个目录可以包含子目录和文件。

支持层次化的文件管理,适用于文件数量多且结构复杂的情况。

2、当前目录与目录检索

当前目录又叫工作目录;用户可以根据需要修改工作目录。

路径:

  • 绝对路径
  • 相对路径

三、目录项和目录文件

目录项是管理目录的基本数据结构,一般是定长的。

简单文件系统的一个目录项对应一个FCB的部分或全部;目录文件就是目录项的有序集合,通常可保存在外存储设备上。

1、目录项

一个目录项必定对应一个文件。

2、目录文件

目录文件以文件的形式保存起来,这个文件就称为目录文件。它是每项记录长度固定的记录式文件。

四、目录项分解法

一个FCB一般需要占用很多存储单元,这样往往导致目录文件也很大,检索时速度慢。

目录分解法将目录项(FCB)分为两个部分:

  • 符号目录项(次部):文件名、文件号
  • 基本目录项(主部):除文件名、文件号外的FCB全部信息

优点:减少访盘次数,提高了文件目录的检索速度。

五、UNIX的文件目录实现

UNIX的V7文件系统。

每个目录项(对应一个文件)包含2个域:文件名(14字节 )和i节点好(2字节)。

UNIX普通文件的物理结构是三级索引结构。

根目录的i节点存放于磁盘上的任意的一个固定位置。

六、FAT文件系统的实现

File Allocation Table是一个简单的文件系统;版本有FAT12、FAT16、FAT32,其中的数字代表表示磁盘块地址的二进制位数;

FAT中物理地址以簇为单位分配,簇号又叫物理块号。

  • 文件分配表(FAT)位于卷开头。
  • 为防止损坏,FAT FS保存了2个文件分配表,一遍故障时恢复。
  • FAT和根目录放在磁盘上的一个固定位置。

(1)引导扇区Boot Sector

包含卷的各种信息;x86计算机上,主引导记录使用系统分区上的引导扇区来加载OS的核心文件。

(2)文件分配表

包含卷上每个簇的以下信息:

  • 未使用/空闲簇:0x0000
  • 被文件所使用的簇
  • 坏簇:0xFFF7
  • 文件结束标识/文件中的最后一簇:0xFFFF8 - 0xFFFF

(3)根目录

与其他目录唯一区别是:根目录存放在磁盘上一个特殊的位置且具有固定的大小。

第四节 文件存储空间管理

一、磁盘空间管理

只读存储器(如:CD-ROM)物理上就不可重复使用。

为了进行存储空间的分配与回收,在外存设备上设置了空闲空间登记表,该表可以动态跟踪该外存设备上还没分配 的空闲块数目及块号。

空闲空间登记表不一定以二维表的形式实现;通常把空闲空间登记表放在存储介质上,会经常对其进行当问和修改。

二、磁盘空间的分配与回收算法

1、位示图

基本思想:利用一串二进制位(bit)的值来反映磁盘空间的分配使用情况。在位示图中,每一个磁盘中的物理块与1个二进制位对应,若某块空间空闲则二进制位为0;若已分配则为1。

位示图对孔家按的分配情况描述能力强,占用空间小,因此可复制到内存,使得查找方便又快速;它适用于各种物理结构的文件系统。

2、空闲块表

专门为空闲块建立一张表,记录了外存全部空闲的物理块,包括第一个空闲块号和空闲块个数;特备适合物理结构是顺序结构的文件系统。

【操作系统】第六章 文件系统_物理结构_06

3、空闲块链表

空闲块连成一个链表,用一个空闲块首指针指向第一个空闲块,随后的每个空闲块中都含有指向下一个空闲块的指针,最后一块的指针为空代表链尾。

【操作系统】第六章 文件系统_夏明亮_07

特点:实现效率低,要遍历整张链表,必须读每一个空闲块,需要大量I/O时间;以块为单位分配与释放,申请时从链首取,释放后接入链尾;节省空间,但申请和回收都慢,效率低下。

4、UNIX系统的空闲块成组链表

这是对空闲块链表的一种改进方案;将n个空闲块的地址存放在第一个空闲块中,其余n-1个空闲块实际上都是空闲的。

假设每100和空闲块一组,第一组的100个空闲块号放在第二组的第一个块上;第二组的100个空闲块号放在第三组的第一个快上,以此类推;组与组间形成链接关系。

在最后一组中,第二个单元填充0,标识这是最后一组。

不足100个块的组的所有块号,通常放在内存的一个专用块中。

系统初始化时先将专用块内容读到内存,需要分配时就直接在内存中查找空闲块,在只剩下第一个空闲块之前,登记在该块中的下一组块号及块数保存到专用块中,随后可将剩下的这个第一个块分配出去,以此类推。

示例
位示图(Bitmap)

假设一个磁盘有16个块,块大小为4KB,位图如下:

位示图: 0 1 1 0 0 0 1 0 0 1 1 0 0 1 0 1
 块地址: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
  • 1.
  • 2.
  1. 分配一个4KB的块
  • 查找第一个0位的位置,将其置为1,我们这个例子是分配块0。
  • 位示图更新为:
分配一个4KB的块:
 - 查找第一个0位的位置,将其置为1,分配块0。
 - 位示图更新为:
 
 位示图: 1 1 1 0 0 0 1 0 0 1 1 0 0 1 0 1
 块地址: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  1. 释放块0
  • 将位3位置为0,表示块3已空闲。
  • 位示图更新为:
位示图: 0 1 1 0 0 0 1 0 0 1 1 0 0 1 0 1
 块地址: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
  • 1.
  • 2.
文件分配表(FAT)

假设一个文件分配表如下:

FAT:
 块号:  0  1  2  3  4  5  6  7  8  9
 值:   2  4  -1  -1  -1  -1  7  -1  -1  -1
  • 1.
  • 2.
  • 3.
  1. 文件A
  • 存储在块0、2,结束标记-1。
  • 读取文件A:块0 -> 块2 -> 结束。
  1. 文件B
  • 存储在块1、4,结束标记-1。
  • 读取文件B:块1 -> 块4 -> 结束。

第五节 实现文件系统的表目

当用户申请打开一个文件时,系统需要再内存中为该用户保存一些必要的信息,这些信息以表格栏目中内容的形式出现,称之为"表目";一些重要的表目有:

一、系统打开文件表

用于保存已打开文件的FCB,通常放在内存中;还保存了共享计数、修改标志信息。

共享计数:进程数

修改标志:已修改则在关闭时需要先将FCB写回磁盘。

二、用户打开文件表

每个进程都有一个"用户打开文件表";包括:

  • 文件描述符
  • 打开方式
  • 读写指针
  • 系统打开文件表入口

FCB中记录"用户打开文件表"的位置;实际上用户打开文件表指向了系统打开文件表;若多个进程共享同一个文件,则一定会有多个用户打开文件的表目对应着系统打开文件表的同一入口。

文件控制块(File Control Block, FCB)

FCB的作用

文件控制块(FCB)是操作系统用来管理文件的一个数据结构,它包含了与文件有关的各种信息,包括文件名、文件大小、文件位置、权限等。FCB可以理解为文件在系统中的“身份证”。

FCB包含的信息

一个典型的FCB可能包含以下字段:

  1. 文件名(File Name):文件的名称。
  2. 文件标识符(File ID):系统为文件分配的唯一标识符。
  3. 文件位置(File Location):文件在磁盘上的起始位置和长度。
  4. 文件大小(File Size):文件的总字节数。
  5. 创建时间和修改时间(Creation Time and Modification Time):文件的创建和最后修改的时间戳。
  6. 文件类型(File Type):文件的类型(如普通文件、目录、设备文件等)。
  7. 文件权限(File Permissions):文件的访问权限(如读、写、执行权限)。
  8. 链接计数(Link Count):指向该文件的目录条目的数量。
  9. 文件属性(File Attributes):文件的其他属性,如是否是只读、是否隐藏等。

FCB的存储位置

FCB通常存储在两种地方:

  1. 内存中的FCB表:内存中的FCB表(如UNIX中的i节点表)包含了当前打开的文件的FCB。
  2. 磁盘上的FCB:磁盘上的FCB(如FAT文件系统中的目录条目)永久存储文件的元数据。


文件创建

  1. 用户请求创建文件。
  2. 操作系统分配一个新的FCB,并填充文件的相关信息。
  3. 将FCB存储在磁盘上的适当位置。
  4. 在当前目录中添加一个目录条目,指向新创建的FCB。

文件打开

  1. 用户请求打开文件。
  2. 操作系统在当前目录中查找文件名。
  3. 获取对应的FCB,将其加载到内存中的FCB表。
  4. 返回一个文件描述符,供后续文件操作使用。

文件读写

  1. 用户通过文件描述符请求读写文件。
  2. 操作系统使用文件描述符查找对应的FCB。
  3. 根据FCB中的文件位置和大小信息执行读写操作。

文件关闭

  1. 用户请求关闭文件。
  2. 操作系统从内存中的FCB表中移除对应的FCB。
  3. 更新磁盘上的FCB信息(如最后修改时间)。

第六节 文件和目录操作

一、典型的文件操作

通常由系统调用实现。

常用操作:

1、建立文件creat

实质:建立FCB,并建立必要的存储空间。

2、打开文件open

将FCB送入内存。

3、读文件read

4、写文件write

把内存中指定单元的数据作为指定的一个记录写入指定的文件中,系统还将为其分配物理块,以便把记录信息写到外存。

5、关闭文件close

修改FCB的共享用户数(减1);若内容被修改过则写回外存。

6、删除文件delete

收回文件所占FCB和物理块等资源。

7、指针定位seek

二、典型的目录操作

与文件操作类似,通常由系统调用实现。

注意:UNIX中'.'代表当前目录;'..'代表根目录。

  • create:创建
  • delete:删除;只有为空方可删除(UNIX)
  • opendir:打开
  • closedir:关闭,打开后不再使用了则应该关闭。
  • readdir
  • rename:重命名
  • link:链接
  • unlink:解除链接

第六节 文件和目录操作-结合ChatGPT整理

包括对文件和目录的创建、删除、读取、写入、重命名等操作。

文件操作

文件操作是指对文件进行各种管理和操作的过程,主要包括以下几种操作:

1. 文件创建(Create)

创建文件的操作用于在文件系统中生成一个新的文件。这个过程通常包括以下步骤:

  • 分配一个新的文件控制块(FCB)。
  • 在FCB中记录文件的元数据(如文件名、创建时间、初始大小等)。
  • 在目录结构中添加一个指向新FCB的目录条目。

示例代码:

int createFile(FileSystem *fs, char *fileName, int permissions) {
     int fcbIndex = allocateFCB(fs);
     if (fcbIndex == -1) return -1; // 分配失败
 
     FCB *fcb = &fs->fcbs[fcbIndex];
     fcb->permissions = permissions;
     fcb->createTime = getCurrentTime();
     fcb->modifyTime = fcb->createTime;
     fcb->fileSize = 0;
     fcb->linkCount = 1;
     fcb->fileType = 'F';
 
     int dirIndex = findEmptyDirectoryEntry(fs);
     if (dirIndex == -1) return -1;
 
     DirectoryEntry *dirEntry = &fs->dirEntries[dirIndex];
     strcpy(dirEntry->fileName, fileName);
     dirEntry->fcbIndex = fcbIndex;
 
     return 0;
 }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
2. 文件打开(Open)

打开文件的操作用于获取文件的访问权限,使文件进入可操作状态。主要步骤:

  • 在目录结构中查找文件名对应的目录条目。
  • 读取目录条目中的FCB。
  • 将FCB加载到内存中的打开文件表中。

示例代码:

int openFile(FileSystem *fs, char *fileName) {
     int dirIndex = findDirectoryEntry(fs, fileName);
     if (dirIndex == -1) return -1; // 文件不存在
 
     DirectoryEntry *dirEntry = &fs->dirEntries[dirIndex];
     int fcbIndex = dirEntry->fcbIndex;
 
     // 加载FCB到内存中的打开文件表
     openFileTable[currentOpenFileCount++] = &fs->fcbs[fcbIndex];
     
     return fcbIndex;
 }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
3. 文件读取(Read)

读取文件的操作用于从文件中读取数据。主要步骤:

  • 确定读取位置和读取长度。
  • 从文件系统中读取指定位置的数据块。

示例代码:

int readFile(FileSystem *fs, int fileDesc, char *buffer, int size) {
     FCB *fcb = openFileTable[fileDesc];
     int startBlock = fcb->startBlock;
     
     // 读取数据块
     readBlocks(startBlock, buffer, size);
     
     return size;
 }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
4. 文件写入(Write)

写入文件的操作用于将数据写入文件。主要步骤:

  • 确定写入位置和写入长度。
  • 将数据写入文件系统的指定位置。
  • 更新文件的元数据(如修改时间、文件大小等)。

示例代码:

int writeFile(FileSystem *fs, int fileDesc, char *buffer, int size) {
     FCB *fcb = openFileTable[fileDesc];
     int startBlock = fcb->startBlock;
     
     // 写入数据块
     writeBlocks(startBlock, buffer, size);
     
     // 更新元数据
     fcb->modifyTime = getCurrentTime();
     fcb->fileSize += size;
     
     return size;
 }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
5. 文件关闭(Close)

关闭文件的操作用于将文件从可操作状态转变为不可操作状态。主要步骤:

  • 将内存中的FCB信息写回到磁盘。
  • 从打开文件表中移除该文件的FCB。

示例代码:

int closeFile(FileSystem *fs, int fileDesc) {
     FCB *fcb = openFileTable[fileDesc];
     
     // 写回FCB信息
     writeFCBToDisk(fcb);
     
     // 从打开文件表中移除
     openFileTable[fileDesc] = NULL;
     
     return 0;
 }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

目录操作

目录操作是指对目录进行各种管理和操作的过程,主要包括以下几种操作:

1. 目录创建(Create Directory)

创建目录的操作用于在文件系统中生成一个新的目录。主要步骤:

  • 分配一个新的目录条目。
  • 在目录条目中记录目录的元数据(如目录名、创建时间等)。
  • 在父目录中添加一个指向新目录的目录条目。

示例代码:

int createDirectory(FileSystem *fs, char *dirName) {
     int dirIndex = findEmptyDirectoryEntry(fs);
     if (dirIndex == -1) return -1; // 分配失败
 
     DirectoryEntry *dirEntry = &fs->dirEntries[dirIndex];
     strcpy(dirEntry->fileName, dirName);
     dirEntry->isDirectory = 1;
 
     return 0;
 }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
2. 目录打开(Open Directory)

打开目录的操作用于获取目录的访问权限,使目录进入可操作状态。主要步骤:

  • 在父目录中查找目录名对应的目录条目。
  • 读取目录条目中的信息。

示例代码:

int openDirectory(FileSystem *fs, char *dirName) {
     int dirIndex = findDirectoryEntry(fs, dirName);
     if (dirIndex == -1) return -1; // 目录不存在
 
     DirectoryEntry *dirEntry = &fs->dirEntries[dirIndex];
     
     return dirIndex;
 }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
3. 目录读取(Read Directory)

读取目录的操作用于获取目录中的文件和子目录列表。主要步骤:

  • 遍历目录中的所有条目。
  • 返回文件和子目录的列表。

示例代码:

int readDirectory(FileSystem *fs, int dirDesc, DirectoryEntry *buffer, int size) {
     DirectoryEntry *dirEntry = &fs->dirEntries[dirDesc];
     int count = 0;
 
     for (int i = 0; i < fs->entryCount; i++) {
         if (fs->dirEntries[i].parentIndex == dirDesc) {
             buffer[count++] = fs->dirEntries[i];
             if (count >= size) break;
         }
     }
 
     return count;
 }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
4. 目录关闭(Close Directory)

关闭目录的操作用于将目录从可操作状态转变为不可操作状态。主要步骤:

  • 将内存中的目录条目信息写回到磁盘。
  • 从打开目录表中移除该目录的条目。

示例代码:

int closeDirectory(FileSystem *fs, int dirDesc) {
     // 从打开目录表中移除
     openDirectoryTable[dirDesc] = NULL;
     
     return 0;
 }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

文件和目录的高级操作

1. 文件重命名(Rename)

重命名文件的操作用于修改文件的名称。主要步骤:

  • 在目录中查找旧文件名对应的目录条目。
  • 修改目录条目中的文件名为新文件名。

示例代码:

int renameFile(FileSystem *fs, char *oldName, char *newName) {
     int dirIndex = findDirectoryEntry(fs, oldName);
     if (dirIndex == -1) return -1; // 文件不存在
 
     DirectoryEntry *dirEntry = &fs->dirEntries[dirIndex];
     strcpy(dirEntry->fileName, newName);
     
     return 0;
 }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
2. 文件删除(Delete)

删除文件的操作用于从文件系统中移除文件。主要步骤:

  • 在目录中查找文件名对应的目录条目。
  • 释放文件的存储空间。
  • 从目录中移除该目录条目。

示例代码:

int deleteFile(FileSystem *fs, char *fileName) {
     int dirIndex = findDirectoryEntry(fs, fileName);
     if (dirIndex == -1) return -1; // 文件不存在
 
     DirectoryEntry *dirEntry = &fs->dirEntries[dirIndex];
     freeBlocks(dirEntry->startBlock);
     removeDirectoryEntry(fs, dirIndex);
     
     return 0;
 }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
3. 目录删除(Delete Directory)

删除目录的操作用于从文件系统中移除目录。主要步骤:

  • 在父目录中查找目录名对应的目录条目。
  • 确保目录为空(没有子文件和子目录)。
  • 从目录中移除该目录条目。

示例代码:

int deleteDirectory(FileSystem *fs, char *dirName) {
     int dirIndex = findDirectoryEntry(fs, dirName);
     if (dirIndex == -1) return -1; // 目录不存在
 
     if (!isDirectoryEmpty(fs, dirIndex)) return -1; // 目录不为空
 
     removeDirectoryEntry(fs, dirIndex);
     
     return 0;
 }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

第七节 文件系统的性能

FS的物理基础是磁盘设备,需要考虑其:

  • 效率
  • 速度
  • 可靠性

设计FS应尽可能减少访盘次数。

一、磁盘高速缓存

思想:系统在内存中保存一些磁盘块,这些磁盘块逻辑上属于磁盘,内存的这一块区域称为"高速缓存"。

运行时,系统检查所有访问请求,检查所需文件块是否在高速缓存中,若在则直接访问;否则访问磁盘并读入高速缓存,再复制到其他区域;若高速缓存已满则按一定的算法淘汰。

高速缓存中的内容需要定期写回缓存;若写回前发生错误,则会状态不一致;这类问题统称为文件系统一致性问题

1、记录的成组

需要使用内存缓冲区。

把若干个逻辑记录合成一组存放一个物理块的工作称为"记录的成组",每个块中的逻辑记录个数称为"块因子"。

记录的成组再不同的存储介质上进行信息转储是很有用的;它可以提高磁盘利用率(多个小的逻辑记录合成一个大的组后放入物理块);减少启动外设的次数。

2、记录的分解

一组逻辑记录中把其中一个逻辑记录分离出来的操作,也需要使用内存缓冲区。

某文件的物理块的全部信息读入内存缓冲区,此时包含了多个逻辑记录,需要先分解后再送入用户工作区。

  • 定长记录:按长度即可完成分解。
  • 不定长记录:根据记录的长度控制信息计算

二、RAID技术

Redundant Arrays of Inexensive/Independent Disk:廉价/独立冗余磁盘阵列。

解决问题的原理:

  • 低速:RAID采用并行技术进行提速。
  • 可靠性:RAID采用镜像和数据校验技术解决。

RAID 0:简单,无数据校验的条带化技术,将存储块按分散、并行地存储在所有磁盘中;不提供冗余,一旦任一磁盘损坏将无法恢复。

RAID 1:采用镜像技术提高可靠性;将数据完全一致地写入两块磁盘中,100%冗余,互为备份,磁盘利用率50%;写入速度会受影响,读取速度不变;成本高。

【操作系统】第六章 文件系统_夏明亮_08

RAID 0+1:结合了RAID 0和RAID 1的优点;先做数据的分块再做镜像。同时将数据写入两个磁盘阵列中,若其中一个阵列损坏不影响系统使用。

RAID 1+0:先做镜像在分块。

RAID 0+1具有更好的容错能留。

【操作系统】第六章 文件系统_物理结构_09

RAID 2和RAID 3原理与RAID 0基本相似;分别以"位"和"字节"作为并行单位。

RAID 4:是对RAID 3的改进,并行单位是"块"。

RAID 5:与RAID 4相同,但是校验码以"块"为单位与数据块一起随机存放在不同的磁盘中,没有采用专用的校验盘,写操作可同时发生在不同的磁盘上,因此没有RAID 4的并发写入瓶颈。磁盘数量增加,并行能力随之增加;至少需要三块磁盘。

【操作系统】第六章 文件系统_夏明亮_10

对比:

【操作系统】第六章 文件系统_文件系统_11


第八节 文件共享、保护

防止未授权使用和被破坏。

一、文件共享

一个文件可以允许多个用户同时使用:

  • 节省空间
  • 免除复制工作
  • 减少重复劳动
  • 减少实际输入输出文件的次数
  • 利用文件共享可实现进程通讯
(1)文件可以同时使用

必须实施同步控制,一般允许同时读;不允许同时读和写;也不允许同时写。

(2)文件不允许同时使用

任何时刻只允许一个用户使用,其他用户关闭后方方可使用。

共享形式
  • 文件被多个用户使用,权限控制。
  • 文件被多个程序使用,但分别用自己的读写指针。
  • 文件被多个程序使用,但共享读写指针。

二、文件存取控制

文件可能的受损原因:

  • 灾祸:火灾、水灾、战争、暴乱、老鼠咬断线缆部件等。
  • 硬件或软件故障。
  • 人为出错。

常用办法:建立副本和定时转储等办法。

  1. 建立副本:多个介质,可同类或不同类。
  2. 定时转储:每隔一段时间转储,用转储数据恢复的缺点是故障时刻到上次转储时刻中间的数据会丢失。
  3. 规定文件的存取权限
  • 采用树形目录结构(按目录)
  • 存取控制表(可按文件/子目录)

三、UNIX的文件使用权限管理方案

1、存取控制矩阵

用二维矩阵实现控制;其中一维代表用户,另一维代表文件,交点代表用户对文件的权限(R、W、E)。

当用户向文件系统提出存取要求时,由存取控制验证模块根据矩阵判定。

特点:概念简单,实现比较容易。

但当用户和文件较多是,矩阵会非常大,占用太多内存,且扫描矩阵开销很大。

2、二级存取控制

设立两个存取级别,第一级用户划分为不同的用户组;第二级进行权限操作的识别。

【操作系统】第六章 文件系统_逻辑结构_12

3、UNIX中的文件存取权限

权限划分两级:

  • 第一级:
  • 文件属主:owner
  • 属主的同组用户:group
  • 其他用户:other
  • 第二级:
  • 读:read/R
  • 写:write/W
  • 执行:execute/E
  • 无权限:-