# 文件与文件系统

# 文件

文件是操作系统对所存储的信息对外提供的统一逻辑视图,是由文件名标识的一组存储在二级存储设备上的信息的集合。

# 文件名

文件名通常由文件名称和扩展名称组成

# 文件属性

  • 文件名:唯一用户可读信息
  • 文件标识:文件系统内唯一标识
  • 类型:普通文件、目录文件、设备文件
  • 位置:指向文件的位置,包括设备以及设备上的位置
  • 大小:当前长度和允许的最大长度
  • 权限:访问控制信息
  • 时间:文件创建时间,最后修改时间,最后使用时间等。

# 文件操作

  • 创建文件 (create)
    • 从文件系统中找到存放文件的空间(空间分配问题)
    • 在目录中为该文件添加新目录项
  • 写文件 (write)
    • 给出文件名和需要写入文件的信息
    • 文件系统查找目录,从文件目录项中找到文件的位置
    • 文件系统保存了一个写指针,指出下一个写操作开始的位置
  • 读文件 (read)
    • 给出文件名以及内存地址,用于存放读出的下一个文件块
    • 文件系统查找目录,找到对应的文件目录项
    • 系统保存一个读指针,指出下一个读操作开始的位置
    • 读指针每个进程都不一样
  • 重定位 (repositioning)
    • 查找文件目录,找到对应的目录项,将当前文件位置指针修改为给定的值
  • 删除文件 (delete)
    • 查找文件目录,找到给定文件名对应的目录项
    • 释放文件所占用的所有空间
    • 删除对应的目录项
  • 清空文件
    • 删除文件内容,但保留其属性(长度除外)

# 文件存取方式

  • 顺序存取
    • 存取操作在上次的基础上进行
    • 系统设置读写指针,指向要读出或写入的字节位置或记录位置。
  • 直接存取
    • 快速地以任意次序直接读写某条记录,对文件读 / 写的次序没有任何限制
  • 索引存取
    • 在索引存取中,文件包含一个索引,该索引存储了数据块的位置信息。通过索引,可以直接跳转到文件中的特定数据块。

# 文件系统

通常把文件与管理信息资源的管理程序的集合称为文件系统

# UNIX/Linux 的文件类型

  • 普通文件
  • 目录文件:由文件目录所构成的用来维护文件系统结构的系统文件

# 文件目录

# 文件目录数据结构 -- 文件控制块 FCB

文件控制块是文件系统为每个文件建立的唯一管理数据结构,一般包括:

  1. 文件标识和控制信息
    • 文件名、用户名、文件存取权限、访问控制权限、文件类型等
  2. 文件逻辑结构信息
    • 记录类型、记录个数、记录长度、成组因子等
  3. 文件物理结构信息
    • 文件所在设备名、文件物理结构类型、记录存放在辅存中的块号或文件信息首块盘块号,文件索引的位置等
  4. 文件使用信息
    • 共享文件的进程数,文件修改情况,文件最大长度和当前大小
  5. 文件管理信息
    • 文件建立日期,最近修改日期,最近访问日期等

基于 FCB 可以方便地实现文件的按名存取

  • 创建文件时,为其建立一个 FCB,用来记录文件的属性信息
  • 存取此文件时,先找到其 FCB,再找到文件信息盘块号或首块物理位置

# 目录文件

目录文件至少包含两个目录项

  • 当前目录项
  • 父目录项

文件目录的基本功能是将文件名转换成此文件信息在磁盘上的物理位置

# 文件目录结构

# 单级目录结构

所有用户都共用一个目录

缺点:

  • 名字易于重复
  • 用户没有独立的目录,不利于共享和保护

image-20240117115524330

# 两级目录结构

将文件目录分成主文件目录 (Master File Directory, MFD) 和用户文件目录(User File Directory, UFD) 两级

解决多用户之间的文件重名问题,文件系统可以在目录上实现访问限制。但是两级目录结构缺乏灵活性,不能对文件分类

image-20240117115613613

# 树形目录结构
  • 目录可以有任意多的层次
  • 目录可以包含子目录,也可以包含文件
  • 每个文件只有一个父目录
  • 树形目录结构可便于实现文件分类,但不便于实现文件共享。每个用户都有各自的 “当前目录”, 登录后自动进入该用户的 “当前目录”
  • 在树形目录中查找一个文件,需要按路径名逐级访问中间结点,这就增加了磁盘访问次数,无疑将影响查询速度。

image-20240117115711275

为了解决文件共享问题,Linux 提供了硬链接和软链接,Windows 提供了快捷方式等实现方法。

硬链接是指通过文件系统将一个文件关联到另一个文件,使它们共享相同的数据块。从文件系统的角度看,所有的硬链接文件都是相等的,它们共享相同的 inode 和数据块。

image-20240117120452073

软链接是一个特殊类型的文件,其中包含指向另一个文件或目录的路径。软链接本身有一个独立的 inode,其内容是指向目标文件的路径。

软链接可以看成是 Windows 下的快捷方式

image-20240117120500025

# Linux 下的目录项结构

文件名和文件属性分离,其它信息单独组成一个数据结构,称为索引节点 inode, 其位置由 inode 号标识

  • 每个文件或子目录都在父目录文件中有一条目录项

  • 每个目录项包含两个字段

    • 文件名

    • i-node 号:指出存放文件属性信息的 inode 节点号

  • 每个磁盘块可以存放几十个基本目录项

image-20240117121306334

  • 引导块
    • 位于文件卷最开始的第一扇区,该 512 字节是文件系统的引导代码,为根文件系统所特有,其他文件系统这 512 字节为空
  • 超级块
    • 位于文件系统第二扇区,紧跟引导块之后,用于描述本文件系统的结构和管理信息。如 inode 节点所占盘块数、文件数据所占的盘块数等
  • 磁盘 inode 区
    • 位于超级块之后,长度由超级块中的 inode 所占盘块数决定
    • 每个 inode 用于描述文件属性中除文件名之外的属性,包括文件的长度、属主、物理数据块号等;
  • 数据块
    • 分为目录文件数据块和普通文件数据块
    • 目录文件数据块中存放的是目录项的集合
    • 普通文件数据块存放的是文件数据

# 文件的逻辑组织方式

# 流式文件

又称无结构文件

文件内的数据不再分记录,而是看成字节流

大多数现代操作系统如 WINDOWS, UNIX, LINUX 只提供流式文件

# 记录式文件

文件是一组记录的集合

数据通过记录的地址或关键字进行存储,可以直接访问文件中的特定记录而不必按照顺序逐个读取。

# 成组与分解

逻辑记录是按信息在逻辑上的独立含义由用户所划分的单位,而块是系统划分的存储介质上区域

成组:若干逻辑记录合并成一组,写入一块,每块中的逻辑记录的个数称为成块因子

分解:从读进内存缓冲区的物理块中分解出逻辑记录的过程

# 文件的物理组织方式

# 顺序文件 / 连续文件

文件中逻辑上连续的信息存放到物理介质的相邻物理块上形成顺序结构

image-20240117122647298

优点:

  • 顺序存取和随机存取时速度较快

缺点

  • 建立文件之前需要确定文件的长度,以分配存储空间
  • 修改、插入和添加文件记录较为困难
  • 对于变长记录的处理很困难
  • 会产生外部碎片

# 连接文件

文件在物理上被组织成物理块的链表,分配给一个文件的物理块在空间上可能是分散的
每个块的连接字指出文件的下一个物理块位置

image-20240117122714061

优点:

  • 文件的逻辑顺序独立于存储空间的物理块顺序
  • 易于记录的增、删、改
  • 易于文件扩充

缺点

  • 仅适宜于顺序存取
  • 随机存取速度慢,需要从头开始查找
  • 连接字与数据混放,破坏了数据块的完整性
  • 连接字需要占用额外的空间

# FAT(File Allocation Table)文件分配表

把连接指针从数据块中分离出来,单独建立一个指针数组 PTRS[n], n 为组成磁盘连接文件物理块的总块数

image-20240117125210608

# 索引文件

为每个文件建立索引,给出逻辑记录或逻辑块号到物理块号的映射

索引表可以存放在文件控制块中,也可以让索引表作为物理块单独驻留在磁盘的任意位置,而 FCB 中仅包含索引表的地址

image-20240117125401188

优点

  • 随机存储速度快
  • 便于信息的增、删、改

缺点

  • 索引表的空间开销

# 文件空间管理方法

# 位示图

磁盘空间由固定大小的块组成,可方便地使用位示图管理

  • 每一字位对应于一个物理块,字位值为 1 表示被占用,0 表示空闲。

image-20240117125747509

例题

image-20240117132209121

# 空闲区表

常常用于连续文件,将空闲区存储块的位置及其连续空闲的块数构成一张表

# 空闲块链

把所有空闲块连接在一起,系统保持指针指向第一个空闲块,每一空闲块中包含指向下一个空闲块的指针

# 空闲块成组管理

每 100 块划分一组,每组第一块登记下一组空闲块的物理盘块号和空闲块总数

# 文件系统调用的实现

  • 创建和删除文件
  • 打开和关闭文件
  • 读 / 写文件
  • 文件共享
  • 主存映射文件

主存活动 inode 表

  • 磁盘 inode 的所有信息,如物理块地址

  • 主存 inode 的状态

    • inode 是否上锁

    • inode 数据是否改变

    • 文件数据是否改变

  • 文件系统的逻辑设备号

  • inode 号

  • 引用数:i_count

    • 多少个系统打开文件表项指向该主存 inode

# 用户打开文件表

每个进程有一个用户文件描述符表,用于描述所有打开的文件,称为用户打开文件表

每个用户打开文件表中的表项都指向一个内核系统打开文件表中的表项

# 系统打开文件表

内核有一个系统打开文件表,用于存放文件访问信息

# 文件系统调用原理

# 文件创建

  1. 为新文件分配索引节点和活动索引节点,并把索引节点编号与文件分量名组成新目录项,记到目录中。
  2. 在新文件所对应的活动索引节点中置初值,如置存取权限 i_mode,连接计数 i_nlink 等。
  3. 分配用户打开文件表项和系统打开文件表项,置系统打开文件表项初值,如读写位移 f_offset 清 “0”。
  4. 把各表项及文件对应的活动索引节点用指针连接起来,把文件描述字 fd 返回给调用者。

# 文件删除

删除的任务:

  • 把指定文件从所在的目录文件中去除。
  • 如果没有连接用户 (i_nlink 为 “1”),还要把文件占用的存储空间释放。
  • 系统调用形式为:unlink (filenamep)。
  • 在执行删除时,必须要求用户对该文件具有 “写” 操作权。

# 文件打开

  1. 检索目录,把它的外存索引节点复制到活动索引节点表。
  2. 根据参数 mode 核对权限,如果非法,则这次打开失败。
  3. 当 “打开” 合法时,为文件分配用户打开文件表项和系统打开文件表项,并为系统打开文件表的表项设置初值。通过指针建立这些表项与活动索引节点间的联系。把文件描述字,即用户打开文件表中相应文件表项的序号返回给调用者

# 文件关闭

  1. 根据 fd 找到用户打开文件表项,再找到系统打开文件表项,释放用户打开文件表项。
  2. 把对应系统打开文件表项中的 f_count 减 1,如果非 0,说明进程族中还有其它进程共享这一表项,不用释放直接返回;否则释放表项,并找到与之连接的主动活动 inode。
  3. 把活动 inode 中的 i_count 减 1,若不为 0,表明还有用户进程正在使用该文件,不用释放而直接返回;否则在把该活动 inode 中的内容复制回磁盘上的相应 inode 后,释放该活动 inode。

# 读文件

  • 系统根据 f_flag 中的信息,检查读操作合法性;
  • 若合法,按活动 i_node 中 i_addr 指出的文件物理块存放地址,从文件当前的位移量 f_offset 处开始,读出所要求的 count 个字节,存放到系统缓冲区中,然后再送到 buf 指向的用户主存区中。

# 文件共享实现

# 文件静态共享

一个文件同时属于多个目录,但实际上文件仅有一处物理存储

# 文件动态共享

文件的动态共享通过引入系统打开文件表来实现,父子进程可以通过共享同一个读写指针来协同工作。

# 文件的符号链接共享

又称软链接,符号链接是一种只有文件名,不指向 inode 的文件