第19讲 文件系统I

从数据块到文件:文件系统如何组织持久化存储

引言

从用户的视角看,存储设备中存在的是文件和目录:文件有名字、大小、类型和权限,目录可以容纳其他文件,应用程序能够按照路径打开、读取、修改或删除它们。

然而,在硬盘或SSD的底层,并不存在天然的“文件”概念。存储设备提供给操作系统的,本质上只是一大片可以按照编号访问的存储块。它不知道某些块属于一张图片,另一些块属于一段视频,更不知道/home/aster/demo.txt这样的路径意味着什么。

因此,文件系统需要完成一次关键的抽象转换:

1
2
3
4
5
底层:一系列编号的数据块

文件系统组织与解释

上层:文件、目录、路径、权限和持久化数据

文件系统的核心任务,就是记录文件由哪些数据块组成,为文件建立名称与层级关系,管理空闲空间,并在设备故障或异常断电后尽可能维持结构的一致性。

围绕“如何定位一个文件的数据”,不同文件系统发展出了不同方案。inode文件系统采用多级索引,FAT使用簇链表,NTFS则围绕MFT、区段和树形索引建立更加统一的元数据体系。它们的具体结构不同,但解决的本质问题相同:如何在有限的元数据开销下,高效地组织数量庞大、大小不一且不断变化的文件。


一、块设备:文件系统面对的物理基础

硬盘和SSD通常被操作系统抽象为块设备。所谓块设备,是指操作系统不会直接要求设备读取某个孤立字节,而是以一整块数据作为基本读写单位。

典型请求可能是:

1
2
读取第1000号块
向第2000号块写入4KB数据

而不是:

1
读取设备上的第83021个字节

机械硬盘需要移动磁头、等待盘片旋转并读取一段连续区域。读取一个字节与读取一小块连续数据相比,机械定位成本几乎没有区别,因此逐字节访问缺乏效率。

SSD虽然不存在磁头和盘片,但闪存也按照页、擦除块等较大单位组织数据。它不能像普通内存一样随意覆盖单个字节,因此同样适合以块设备的形式向操作系统提供接口。

1. 不同层次的“块”

“块”并不是一个只属于某一层的概念。存储系统中存在多种大小可能相同、含义却完全不同的单位。

概念 所属层次 主要作用
硬盘扇区 存储硬件 硬盘实际读写和寻址单位
闪存页或擦除块 SSD内部 闪存编程、读取和擦除单位
文件系统块 文件系统 分配文件空间和记录数据位置
FAT、NTFS等文件系统 由一个或多个扇区组成的空间分配单位
内存页 虚拟内存系统 地址映射、换页和内存保护

文件系统块与内存页都可能是4KB,但不能因此将二者视为同一对象。前者描述持久化存储空间,后者描述内存管理空间。文件被读取时,磁盘块中的内容可能进入页缓存并占用内存页,但这是两个层次之间的数据转移,而不是概念上的等同。


本节核心结论: 文件系统不是直接管理“文件”,而是建立在块设备之上,将底层编号块重新解释成文件与目录。


二、从应用程序到存储设备:文件访问的软件路径

应用程序不会直接操作硬盘扇区。一次文件读取通常需要经过多个软件层次:

这条路径中的各层承担不同职责:

  • VFS虚拟文件系统提供统一的文件操作接口,使应用程序不必关心底层使用的是ext4、FAT还是其他文件系统。
  • 具体文件系统理解磁盘上的实际数据结构,例如inode、目录项、FAT表或MFT。
  • 页缓存在内存中保留最近访问的文件内容,减少重复磁盘I/O。
  • 块层将不同存储设备统一抽象为可编号、可读写的块。
  • I/O调度器合并和排序请求,降低随机访问成本。
  • 设备驱动把通用块请求转换为具体硬件能够执行的命令。

这种分层结构体现了操作系统中常见的抽象原则:上层负责表达“想读取哪个文件”,下层逐渐把这一请求翻译成“读取设备上的哪些块”。

文件系统的作用并不只是保存数据。 它还位于文件名、路径、逻辑偏移和物理块之间,承担完整的解释与映射工作。


三、文件的逻辑形式与物理形式

对于应用程序而言,文件通常表现为一段从偏移量0开始的连续字节序列。文本、图片、视频、源代码和PDF在文件系统眼中并没有本质区别。

文件系统只负责保存字节:

1
2
3
.png字节序列 → 由图片软件解释
.pdf字节序列 → 由PDF阅读器解释
.cpp字节序列 → 由编辑器或编译器解释

文件系统不需要理解图片中的像素、程序中的语句或视频中的帧。数据的语义属于应用层,文件系统只维护字节的持久化、位置和元数据。

1. 逻辑连续不等于物理连续

假设一个文件大小为4GB,文件系统块大小为4KB,那么它需要约:

1
4GB ÷ 4KB = 1,048,576个数据块

如果要求这100多万个块必须连续存放,会出现严重问题:

  • 设备中未必存在足够大的连续空闲区域。
  • 文件增长时,紧邻其后的空间可能已被其他文件占用。
  • 文件创建和删除会不断制造外部碎片。
  • 为扩展文件而整体搬迁数据的成本过高。

因此,现代文件系统通常允许一个文件的数据块分散在设备的不同位置。文件在逻辑上仍然是一段连续字节序列,但其物理块可以不连续。

于是,文件系统必须回答一个关键问题:

给定文件中的某个逻辑偏移,应该到设备上的哪个数据块读取内容?

inode、FAT和MFT正是这个问题的不同答案。


本节核心结论: 文件对应用程序表现为连续字节序列,但其数据可以分散在不同物理块中;文件系统必须保存逻辑位置到物理位置的映射。


四、inode:用多级索引定位文件数据

在许多类Unix文件系统中,文件由inode描述。inode可以理解为文件在文件系统内部的档案记录。

一个inode通常保存两类信息:

  • 文件元数据:

    • 文件类型
    • 文件大小
    • 访问权限
    • 所有者UID和GID
    • 时间信息
    • 硬链接数量
  • 数据定位信息:

    • 直接数据块指针
    • 一级间接指针
    • 二级或更高级间接指针

需要特别注意的是,inode通常不保存文件名。文件名保存在目录项中,由目录项把名字映射到inode编号。

完整关系是:

1
文件名 → inode编号 → inode → 文件数据块

1. 为什么不能保存一个巨大指针数组

假设一个大文件包含100万个数据块,每个块地址占8B,那么仅记录所有块地址就需要:

1
1,000,000 × 8B = 8MB

如果每个inode都预留如此巨大的指针数组,那么即使文件只有几百字节,也要承担大量无用的索引空间。

问题的矛盾在于:

  • 小文件只需要极少的数据块,索引应当尽量简单。
  • 大文件可能包含数百万个块,索引又必须具有扩展能力。

inode通过多级索引解决了这一矛盾。

2. 直接指针与间接指针

一种典型的教学模型包含:

  • 12个直接指针
  • 3个一级间接指针
  • 1个二级间接指针

直接指针直接保存数据块地址,访问时不需要读取额外索引块,因此特别适合小文件。

假设块大小为4KB,12个直接指针可以表示:

1
12 × 4KB = 48KB

一级间接指针指向一个专门保存块地址的索引块。若索引块大小为4KB,每个地址占8B,则一个索引块可以保存:

1
4KB ÷ 8B = 512个指针

一个一级间接指针能够表示:

1
512 × 4KB = 2MB

三个一级间接指针可以表示约6MB文件数据。

二级间接指针先指向一个二级索引块,其中的每个指针再指向一个一级索引块,因此可以表示:

1
512 × 512 × 4KB = 1GB

在这一示例中,最大文件大小约为:

1
48KB + 6MB + 1GB

真实文件系统可能使用三级间接指针,也可能采用extent等更现代的区段机制,但其设计思想相同:小文件使用简单路径,大文件按需增加索引层次。

3. 多级索引的“按需付费”

inode不会为所有文件提前建立完整索引树。

  • 小文件只使用直接指针。
  • 文件继续增长时才分配一级间接索引块。
  • 更大的文件才需要二级或更高级索引。

这种结构让元数据成本与文件大小共同增长。小文件不会承担为大文件准备的索引开销,大文件也不会受到固定指针数量的严格限制。

其代价是,访问文件后部的数据可能需要额外读取一层或多层索引块。不过这些索引块通常可以被缓存,因此实际访问不一定每次都产生完整的磁盘I/O。

4. inode与多级页表

inode索引与多级页表具有相似的结构思想,但服务对象不同。

对比点 inode索引 多级页表
映射关系 文件逻辑块到存储数据块 虚拟页到物理页
索引依据 文件中的逻辑块编号 虚拟地址的各级索引
管理目标 定位文件内容 完成地址翻译和内存隔离
物理连续性 文件块可以离散 物理页可以离散
空间优化方式 按文件大小分配索引结构 按已使用的虚拟地址区域建立页表

二者的共同逻辑是:通过增加有限的间接访问,避免维护一个巨大而稀疏的扁平映射表。


本节核心结论: inode使用直接指针和多级间接指针,在小文件访问效率与大文件扩展能力之间取得平衡。


五、目录、文件名与路径解析

目录同样是一种文件,但其内容不是普通用户数据,而是一组目录项。

目录项至少记录:

1
文件名 + inode编号

例如:

1
2
3
"a.txt"     → inode 100
"photo.png" → inode 205
"project" → inode 310

因此,目录不是一个物理上“装着文件内容的盒子”。它更接近一张名称索引表。子文件的数据仍然存放在各自的数据块中,目录只负责保存名字与inode之间的关系。

1. 路径是如何被解析的

访问/home/aster/demo.txt时,操作系统大致执行以下过程:

  1. 从根目录/的inode开始。
  2. 读取根目录内容,查找名为home的目录项。
  3. 获得home对应的inode编号。
  4. 读取home目录,查找aster
  5. 获得aster目录的inode编号。
  6. 读取aster目录,查找demo.txt
  7. 获得目标文件的inode。
  8. 根据inode中的索引信息定位数据块。

路径解析本质上不是一次完成的字符串匹配,而是逐层读取目录、逐层完成“名字到inode”的转换。

普通目录的名字存放在其父目录中。根目录是整个路径系统的起点,不需要再由另一个父目录为其提供名字。

2. 目录大小取决于目录项,而不是子文件大小

一个包含100个小文件的目录,可能比一个只包含10部大型电影的目录本身更大。

原因在于目录保存的是:

  • 文件名
  • inode编号
  • 文件类型等少量目录项信息

电影文件即使占用数十GB,在目录中也可能只对应一个很短的目录项。目录大小主要由项目数量、文件名长度和目录项结构决定,而不是由子文件内容总量决定。

3. 删除文件首先删除的是名字

从目录中删除文件时,最先消失的是:

1
文件名 → inode编号

的映射关系。

这不意味着数据必然立即被回收。文件系统还需要检查:

  • inode是否仍被其他硬链接引用。
  • 文件是否仍被某个进程打开。
  • inode与数据块是否已经可以安全释放。

因此,文件名被删除、文件对用户不可见和底层数据块被重新分配,可能发生在不同时间。

删除文件的本质首先是解除名称引用,而不是立即擦除每一个数据字节。


六、文件系统在磁盘上的整体布局

文件系统不仅要保存普通文件,还要保存描述自身结构的元数据。格式化的主要作用,也不是简单地把设备全部清零,而是在设备上建立一套可以被文件系统识别和维护的布局。

一个简化的inode文件系统可能包含:

1
2
3
4
5
超级块
数据块分配位图
inode分配位图
inode表
文件数据区域

1. 超级块:文件系统的总说明书

超级块通常记录:

  • 文件系统类型和魔法数字
  • 文件系统块大小
  • 总块数和空闲块数
  • inode总数和空闲inode数
  • 文件系统状态
  • 创建、挂载等信息

魔法数字用于识别数据格式。操作系统读取分区中的特定位置后,可以依据魔法数字判断该区域是否属于自己支持的文件系统。

超级块描述了整个文件系统应该如何被解释。如果超级块严重损坏,操作系统可能无法确定inode表、位图和数据区域的位置,从而无法正常挂载文件系统。因此,很多文件系统会保存超级块的备份副本。

2. inode表:有限数量的文件档案

inode表是一组固定大小的inode记录。

如果文件系统在格式化时创建了5800万个inode,那么它最多只能同时容纳大约5800万个需要inode的对象。即使数据区仍然存在空闲空间,一旦inode耗尽,也无法继续创建新文件。

这解释了一种看似反常的现象:

磁盘容量明明没有用完,系统却提示无法创建文件。

此时耗尽的可能不是数据块,而是inode。

3. inode位图与数据块位图

位图使用一个二进制位表示一个对象是否空闲。

inode位图:

1
2
0:空闲inode
1:已使用inode

数据块位图:

1
2
0:空闲数据块
1:已使用数据块

创建文件时,文件系统从inode位图中寻找空闲inode;文件需要写入内容时,再从数据块位图中寻找空闲块。

这种机制与物理内存的位图分配器非常相似,只是管理对象由内存页变成了文件系统中的inode和数据块。

4. 创建文件时修改了什么

创建一个空文件通常至少涉及:

  1. 在inode位图中分配一个空闲inode。
  2. 初始化inode中的类型、权限、时间等元数据。
  3. 在父目录中增加目录项。
  4. 建立“文件名到inode编号”的映射。

当文件开始写入数据时,还需要:

  1. 从数据块位图中分配数据块。
  2. 在inode中记录数据块位置。
  3. 更新文件大小和时间。
  4. 必要时分配间接索引块。

因此,即使创建的只是一个空文件,也不是简单增加一个文件名,而是需要同时维护多种文件系统元数据。


本节核心结论: 文件系统必须记录自己的整体布局、已用资源和空闲资源;磁盘空间与inode数量是两类彼此独立的有限资源。


七、FAT:用簇链表连接文件数据

FAT是File Allocation Table,即文件分配表。它使用类似链表的方式组织分散的数据簇。

目录项中保存:

1
文件名 + 起始簇号

FAT表中的每一项则记录:

1
当前簇的下一个簇号

例如:

1
2
3
4
5
目录项:FILE1.DAT → 起始簇2

FAT[2] = 4
FAT[4] = 5
FAT[5] = 结束标志

这表示文件的数据位于:

1
簇2 → 簇4 → 簇5 → 结束

读取文件时,系统需要:

  1. 从目录项获得起始簇。
  2. 读取当前簇的数据。
  3. 查询FAT表,获得下一个簇号。
  4. 继续读取,直到遇到文件结束标志。

1. FAT的优势

FAT结构简单,容易实现,也具有较强的跨平台兼容性,因此长期被用于U盘、存储卡和嵌入式设备。

文件增长时,只需要为文件分配新的簇,并把原链尾指向新簇,无须重新建立复杂的索引结构。

2. FAT的局限

FAT的主要问题来自链式结构。

  • 要访问文件后部,通常需要沿簇链逐项查找。
  • 文件越大,链越长,随机访问越不方便。
  • 如果链中的某个表项损坏,后续簇可能全部失去联系。
  • FAT表本身是整个文件系统的关键元数据,损坏后影响范围较大。

传统FAT通常保存两份FAT表,以便在主表损坏时尝试使用备份恢复。

3. FAT32的4GB单文件限制

FAT32的文件大小字段通常使用32位无符号数,最大能够表示:

1
2^32 - 1B

即略小于4GiB。

因此,即使FAT32分区仍有大量空闲空间,也不能保存一个超过这一限制的普通文件。限制来自文件元数据中的大小字段,而不是来自分区剩余容量。

“FAT32”中的32也不意味着分区最大只能是32GB。它主要与FAT表项格式有关,不能与Windows某些格式化工具提供的32GB限制混为一谈。

4. exFAT的改进

exFAT针对更大容量的移动存储设备进行了扩展,包括:

  • 扩大文件大小表示范围,支持超过4GB的文件。
  • 使用空闲空间位图提高分配效率。
  • 支持Unicode长文件名。
  • 使用哈希值辅助目录查找。
  • 使用校验信息提高元数据完整性。

exFAT仍保留了面向移动存储和跨平台使用的定位,但缓解了FAT32在大文件和大容量设备上的局限。


八、NTFS:以MFT统一组织文件元数据

NTFS是New Technology File System,是Windows系统中广泛使用的文件系统。它的核心结构是MFT,即Master File Table,主文件表。

MFT由大量记录组成,其中不仅包括普通文件和目录记录,还包括文件系统自身的元数据记录。

一个文件的MFT记录可以包含:

  • 文件名
  • 文件大小
  • 权限
  • 时间信息
  • 数据所在的簇区段
  • 其他属性

对于足够小的文件,数据本身甚至可以直接存放在MFT记录内部;较大的文件则由MFT记录描述其外部数据位置。

这种设计将文件视为一组属性,使NTFS能够通过较统一的结构管理名称、权限、内容和其他元数据。

1. 区段表示

如果文件占据一组连续簇,没有必要逐个保存:

1
100、101、102、103、104

可以使用一个区段表示:

1
2
起始簇:100
连续长度:5

区段也称extent。对于连续性较好的大文件,区段能够显著减少定位信息的数量。

文件发生碎片化后,则需要用多个区段描述:

1
2
3
起始簇100,长度5
起始簇250,长度8
起始簇900,长度3

因此,与FAT逐簇建立链表相比,区段更适合描述大段连续空间。

2. 为什么文件系统偏爱B树和B+树

文件系统中的查找成本主要来自存储I/O,而不是CPU完成一次关键字比较所需的时间。

普通二叉树的每个节点只有少量分支,数据量增大后树会变得较高。B树或B+树的一个节点可以容纳大量关键字和子指针,因此具有很高的分支因子。

结构 单个节点分支数 树高 典型I/O次数
二叉树 最多2个 较高 较多
B树或B+树 数十至数百个 较低 较少

如果树的一个节点恰好对应一个磁盘块,那么一次读取就可以获得大量索引信息。树越矮,完成查找需要读取的磁盘块就越少。

B树的核心价值并不只是渐进复杂度,而是用高分支因子减少昂贵的存储I/O。

3. MFT镜像与日志

NTFS会为部分重要MFT信息保存镜像,以降低关键元数据损坏后整个文件系统无法使用的风险。

它还使用日志记录元数据修改。若系统在更新目录、分配空间或修改MFT时突然断电,日志可以帮助文件系统判断哪些操作已经完成、哪些操作需要回滚或重新执行。

日志通常不能保证用户文件的所有内容都不丢失,但可以显著降低文件系统结构陷入不一致状态的概率。

4. MFT如何找到自身

MFT本身也被视为一个文件,通常记为$Mft。这会产生一个看似循环的问题:

1
2
3
需要先读取MFT才能找到文件
MFT本身又是一个文件
那么最初如何找到MFT?

NTFS通过自举解决这一问题:

  1. 文件系统引导区域保存MFT初始位置等基础信息。
  2. 系统根据这些固定信息读取MFT的起始部分。
  3. MFT中的$Mft记录再描述MFT自身剩余部分的位置。

系统只需要在固定位置保存一小部分启动信息,之后便可以进入由MFT统一描述的正常文件系统结构。


本节核心结论: NTFS以MFT统一记录文件属性,使用区段和树形索引提高大文件及大目录的访问效率,并通过镜像和日志增强元数据可靠性。


九、inode、FAT与NTFS的设计差异

三类文件系统采取了不同的数据定位方式。

对比点 inode文件系统 FAT NTFS
文件核心记录 inode 目录项和FAT表 MFT记录
文件名位置 目录项 目录项 MFT属性或目录索引
数据定位方式 直接指针和多级索引 簇链表 区段、属性和树形结构
随机访问能力 较好 大文件后部访问较慢 较好
结构复杂度 中等 较低 较高
空闲空间管理 常见位图 FAT或辅助结构 位图等结构
可靠性机制 取决于具体实现 FAT备份 MFT镜像和日志
典型使用环境 Linux等类Unix系统 移动设备、兼容场景 Windows系统

inode和FAT之间最明显的区别,是索引分配与链式分配的区别。

对比点 inode索引 FAT链表
基本思路 从索引结构定位数据块 从起始簇沿链寻找后续簇
随机访问 可以计算并查找对应索引项 通常需要沿链遍历
文件增长 增加数据块和必要的索引块 将新簇接到链尾
损坏影响 一个索引项影响其对应范围 链中断可能使后续簇全部失联
实现复杂度 较高 较低

这几种方案并不存在脱离使用环境的绝对优劣。

  • FAT结构简单、兼容性强,适合移动介质。
  • inode分级索引适合大量不同大小文件,并具有较好的随机访问能力。
  • NTFS以更复杂的元数据和可靠性机制换取功能完整性。

文件系统设计始终是在实现复杂度、访问效率、空间开销、可靠性和兼容性之间作出权衡。


十、文件系统如何解释日常现象

1. 为什么1TB硬盘只显示约931GB

这一现象首先来自十进制和二进制单位差异。

厂商通常按照十进制计算:

1
1TB = 10^12B

而许多操作系统界面过去按照二进制单位换算:

1
1GiB = 2^30B

因此:

1
10^12 ÷ 2^30 ≈ 931.3

厂商标称1TB的设备,对应约931.3GiB。有些界面虽然写作“GB”,实际使用的却是GiB换算方式。

除此之外,格式化还需要占用一部分空间保存:

  • 超级块
  • 分配位图
  • inode表或MFT
  • 文件系统日志
  • 备份元数据
  • 保留区域

因此需要区分两个不同问题:

1
2
3
4
5
1TB变成约931GiB
→ 主要来自十进制与二进制单位换算

文件系统总容量变成用户可用容量
→ 还要扣除元数据和保留空间

2. 为什么文件大小与占用空间不同

“文件大小”表示文件包含的有效字节数量。

“占用空间”表示文件系统实际为其分配的存储块总量。

假设文件系统块大小为4KB,一个605B的文件通常也需要占用完整的数据块:

1
2
文件大小:605B
占用空间:4KB

剩余空间属于块内部无法分配给其他普通文件的区域,称为内部碎片。

一个极小文件还可能同时消耗:

  • 一个inode或MFT记录
  • 一个目录项
  • 位图中的分配标记
  • 日志中的元数据记录

因此,“文件内容只有1B”并不意味着其全部存储成本只有1B。

某些文件系统可能通过小文件内联、压缩、稀疏文件等机制改变实际占用,但这些属于额外优化,不能否定按块分配的基本原则。

3. 为什么复制大量小文件特别慢

复制十万个小文件与复制一个同样总大小的大文件,数据总量可能相同,但文件系统工作量完全不同。

复制每个小文件都可能涉及:

  1. 路径查找。
  2. 打开源文件。
  3. 创建目标目录项。
  4. 分配inode或MFT记录。
  5. 分配数据块。
  6. 更新多个位图或索引结构。
  7. 读取与写入数据。
  8. 更新时间信息。
  9. 关闭文件。
  10. 提交或记录元数据修改。

如果文件数量为十万,这套流程就要重复十万次。小文件还可能分散在不同位置,形成大量零碎I/O。

打包后再复制,则更接近传输一个连续的大文件:

  • 只需创建少量文件系统元数据。
  • 可以进行较长的顺序读写。
  • I/O请求更容易合并。
  • 如果同时压缩,实际传输数据量还可能减少。

大量小文件复制缓慢的主要原因,不是文件内容更多,而是元数据操作次数和离散I/O次数更多。


十一、一次文件读取的完整逻辑

以inode文件系统读取/home/a.txt为例,完整过程可以概括为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
从根目录inode开始

读取根目录数据,查找home

获得home目录inode

读取home目录数据,查找a.txt

获得a.txt的inode

根据直接或间接指针定位数据块

通过块层和设备驱动读取数据

将数据放入页缓存

把所需字节返回应用程序

这一过程揭示了文件系统的真正工作方式。

应用程序发出的请求是:

1
读取/home/a.txt中的一段内容

存储设备能够理解的请求却是:

1
读取若干编号的数据块

文件系统及其上下层软件所做的,就是逐步完成名称、路径、inode、逻辑偏移、数据块和硬件请求之间的翻译。


结论

文件系统的本质,是在块设备提供的原始空间之上建立一套持久化的数据组织规则。

它需要同时解决几个彼此关联的问题:

  • 如何把分散的数据块组织成逻辑连续的文件。
  • 如何通过文件名和路径找到文件。
  • 如何记录文件大小、权限、时间和所有者等元数据。
  • 如何判断哪些inode和数据块已经使用。
  • 如何支持大小差异巨大的文件。
  • 如何在设备损坏或异常断电后维护结构一致性。

inode、FAT和NTFS分别代表了三种不同的组织思路:

  • inode通过直接指针和多级间接索引定位数据块。
  • FAT通过簇链表串联文件内容。
  • NTFS通过MFT、区段和树形索引统一管理文件属性与数据位置。

它们虽然在数据结构上差异明显,却都完成了同一项抽象:把一大片没有名称和层级的编号存储块,转化成用户可以理解和操作的文件世界。

文件并不是存储设备天然提供的实体,而是文件系统利用元数据、索引、目录和分配结构构造出来的逻辑对象。