目录
[1.1 什么是文件系统](#1.1 什么是文件系统)
[1.2 为什么需要文件系统](#1.2 为什么需要文件系统)
[1.3 Linux主流文件系统](#1.3 Linux主流文件系统)
二、磁盘硬件基础
[2.1 磁盘物理结构](#2.1 磁盘物理结构)
[2.2 磁盘存储核心概念](#2.2 磁盘存储核心概念)
[2.3 CHS与LBA寻址方式](#2.3 CHS与LBA寻址方式)
三、文件系统核心概念
[3.1 块(Block):文件存取最小单位](#3.1 块(Block):文件存取最小单位)
[3.2 分区(Partition):磁盘的逻辑划分](#3.2 分区(Partition):磁盘的逻辑划分)
[3.3 inode:文件属性的载体](#3.3 inode:文件属性的载体)
四、Ext2文件系统结构详解
[4.1 块组(Block Group)设计](#4.1 块组(Block Group)设计)
[4.2 块组核心组件](#4.2 块组核心组件)
[4.3 inode与数据块的映射关系](#4.3 inode与数据块的映射关系)
五、目录与路径解析
[5.1 目录的本质](#5.1 目录的本质)
[5.2 路径解析过程](#5.2 路径解析过程)
[5.3 路径缓存(dentry)](#5.3 路径缓存(dentry))
六、分区格式化与挂载
七、软硬链接原理与实践
[7.1 硬链接(Hard Link)](#7.1 硬链接(Hard Link))
[7.2 软链接(Symbolic Link)](#7.2 软链接(Symbolic Link))
[7.3 软硬链接核心区别](#7.3 软硬链接核心区别)
八、总结
一、文件系统概述
文件系统是操作系统管理磁盘存储的核心机制,它为用户和应用程序提供了一套统一的接口,将底层复杂的磁盘硬件抽象为直观的"文件"概念。理解文件系统的原理,是掌握Linux存储管理的关键。
1.1 什么是文件系统
文件系统是组织和管理磁盘数据的软件集合,其核心作用是:
- 定义文件的存储格式(属性与内容的分离存储);
- 管理磁盘空间(空闲块、空闲inode的分配与回收);
- 提供文件的访问接口(创建、读取、修改、删除)。
简单来说,文件系统就是磁盘的"管理软件",没有文件系统的磁盘只是一堆毫无意义的二进制数据,无法被操作系统识别和使用。
1.2 为什么需要文件系统
如果直接操作磁盘扇区,会面临三个核心问题:
- 空间管理混乱:无法高效分配和回收磁盘空间,容易产生碎片;
- 数据查找困难:需要手动记录文件的扇区位置,无法通过"文件名"快速定位;
- 属性管理缺失:文件的权限、创建时间等属性没有统一的存储方式。
文件系统通过引入块、inode、目录等概念,完美解决了这些问题,让用户可以通过"文件名+路径"的方式便捷访问文件。
1.3 Linux主流文件系统
Linux支持多种文件系统,其中Ext(Extended Filesystem)系列是最经典、最常用的:
- Ext2:基础版本,无日志功能,适合对性能要求高、数据安全性要求不高的场景;
- Ext3:在Ext2基础上增加日志功能,提升数据一致性,崩溃后恢复更快;
- Ext4:Ext3的升级版本,支持更大的文件和分区、更快的读写速度、延迟分配等特性,是目前Linux默认的文件系统。
本文以Ext2为核心展开讲解,其核心设计思想完全适用于Ext3/Ext4。
二、磁盘硬件基础
文件系统建立在磁盘硬件之上,为了握文件系统原理,我们得先理解磁盘的物理结构和寻址方式。
2.1 磁盘物理结构
机械硬盘是计算机中唯一的机械设备,其核心结构包括:
- 盘片(Platter):存储数据的圆形磁盘,一个硬盘可能有多个盘片;
- 磁道(Track):盘片表面的同心圆,从外圈到内圈依次编号;
- 扇区(Sector):磁道被划分的扇形区域,是磁盘存储的最小物理单位(默认512字节);
- 柱面(Cylinder):所有盘片上位置相同的磁道组成的圆柱面(磁头移动时"共进退");
- 磁头(Head):每个盘面对应一个磁头,负责读写数据。
2.2 磁盘存储核心概念
- 磁盘容量计算公式 :
容量 = 磁头数 × 柱面数 × 每磁道扇区数 × 每扇区字节数; - 块设备特性:磁盘是典型的"块设备",操作系统不会逐个扇区读写(效率太低),而是以"块"为单位读写;
- 扇区与块的关系:一个块由连续的多个扇区组成(常见4KB = 8个512字节扇区),块是文件系统的最小存取单位。
2.3 CHS与LBA寻址方式
要访问磁盘上的数据,必须先定位到目标扇区,磁盘支持两种寻址方式:
2.3.1 CHS寻址(三维坐标)
- 原理:通过"柱面(Cylinder)+ 磁头(Head)+ 扇区(Sector)"三维坐标定位扇区;
- 适用场景:早期小容量磁盘,地址位数有限(磁头8位、柱面10位、扇区6位),最大支持8GB容量;
- 局限性:地址空间有限,且不同磁盘的磁头数、扇区数可能不同,兼容性差。
2.3.2 LBA寻址(一维线性地址)
- 原理:将整个磁盘的所有扇区按顺序编号(从0开始),用一个线性地址(LBA地址)直接定位扇区,相当于把磁盘看作"扇区数组",LBA是数组下标;
- 优势:地址空间大(支持大容量磁盘),兼容性好,操作系统只需使用LBA,底层转换由磁盘固件完成;
- CHS与LBA的转换公式 :
- CHS转LBA:
LBA = 柱面号 × 磁头数 × 每磁道扇区数 + 磁头号 × 每磁道扇区数 + 扇区号 - 1(扇区号从1开始,LBA从0开始); - LBA转CHS:
柱面号 = LBA // (磁头数 × 每磁道扇区数)、磁头号 = (LBA % (磁头数 × 每磁道扇区数)) // 每磁道扇区数、扇区号 = (LBA % 每磁道扇区数) + 1。
- CHS转LBA:
三、文件系统核心概念
文件系统通过三个核心概念实现对磁盘的管理:块、分区、inode。
3.1 块(Block):文件存取最小单位
- 定义:块是文件系统在分区上划分的固定大小的存储单元(格式化时指定,常见4KB),是文件内容存储的最小单位;
- 特点:块大小一旦确定不可修改,块的编号在分区内唯一;
- 优势:减少磁盘寻道时间(连续块可一次性读取),简化空间管理。
通过stat命令可查看文件的块相关信息:

3.2 分区(Partition):磁盘的逻辑划分
- 定义:将整个磁盘划分为多个独立的逻辑区域,每个分区可单独格式化为不同的文件系统;
- 本质:通过设置"起始柱面"和"结束柱面",将磁盘的一部分逻辑隔离,相当于"磁盘中的磁盘";
- 作用:隔离不同用途的数据(如系统分区、数据分区),提高磁盘管理灵活性。
通过fdisk命令可查看分区信息:

3.3 inode:文件属性的载体
文件的核心是"属性+内容 ",inode(索引节点)就是存储文件属性的核心结构:
- 定义:每个文件对应一个唯一的inode,inode中存储了文件的所有属性(除了文件名);
- inode的核心内容 (Ext2示例):
- 文件权限(i_mode)、所有者ID(i_uid)、组ID(i_gid);
- 文件大小(i_size)、访问时间(i_atime)、修改时间(i_mtime)、创建时间(i_ctime);
- 硬链接数(i_links_count)、占用的块数(i_blocks);
- 数据块指针(i_block[EXT2_N_BLOCKS]):指向存储文件内容的块。
关键点:
- inode号在分区内唯一,是文件的真正标识(文件名只是inode的"别名");
- 文件名不存储在inode中,而是存储在目录文件中;
- 所有文件的inode结构大小相同(通常128字节或256字节),与文件内容大小无关。
通过ls -i命令可查看文件的inode号:

四、Ext2文件系统结构详解
Ext2文件系统将整个分区划分成若干个同样大小的块组 (Block Group),如下图所示。只要能管理⼀个分区就能管理所有分区,也就能管理所有磁盘⽂件。

4.1 块组(Block Group)设计
- 核心思想:将大分区划分为多个小的块组,每个块组独立管理自己的inode和数据块,相当于"分区中的小分区";
- 块组数量 :
块组数 = 分区总块数 ÷ 每块组块数(每块组块数由文件系统自动计算,通常为8192个); - 优势:分散管理压力,减少碎片,提高读写效率。
4.2 块组核心组件
每个块组包含6个核心部分,从前往后依次排列:
4.2.1 超级块(Super Block)
- 作用:存储整个文件系统的全局信息,是文件系统的"总览表";
- 核心内容:块总数、inode总数、空闲块数、空闲inode数、块大小、inode大小、每块组块数、每块组inode数等;
- 备份机制:超级块在每个块组的开头都有一份拷贝(第一个块组必须有),防止单点故障导致文件系统崩溃。
4.2.2 块组描述符表(GDT)
- 作用:每个块组对应一个描述符,存储该块组的具体信息;
- 核心内容:块位图位置、inode位图位置、inode表位置、该块组的空闲块数、空闲inode数等;
- 备份机制:与超级块一样,GDT在每个块组也有拷贝。
4.2.3 块位图(Block Bitmap)
- 作用:用1个比特位标记一个数据块的状态(0=空闲,1=已占用);
- 优势:快速查询空闲块,分配和回收块时只需修改对应比特位,效率极高。
4.2.4 inode位图(Inode Bitmap)
- 作用:用1个比特位标记一个inode的状态(0=空闲,1=已占用);
- 优势:快速查询空闲inode,分配和回收inode时效率极高。
4.2.5 inode表(Inode Table)
- 作用:存储该块组内所有inode的具体内容,是inode的"存储池";
- 特点:inode表占用连续的块,每个inode在表中的位置固定,inode号 = 块组号 × 每块组inode数 + 表内偏移。
4.2.6 数据块(Data Blocks)
- 作用:存储文件的内容数据,是文件系统的"数据存储区";
- 分类 :
- 普通文件数据块:存储文件内容;
- 目录文件数据块:存储目录下的文件名与inode号的映射关系;
- 符号链接数据块:存储软链接的目标路径(短路径直接存在inode中)。
4.3 inode与数据块的映射关系
inode通过i_block数组(共15个元素)指向数据块,,就是用来进行inode和block映射的,这样文件=内容+属性,就都能找到了。

- 12个直接块 :
i_block[0]~i_block[11]直接指向存储文件内容的块,适合小文件(12×4KB=48KB); - 1个一级间接块 :
i_block[12]指向一个"间接块",该块中存储的是数据块的地址,适合中文件(1×(4KB/4B)×4KB=4MB); - 1个二级间接块 :
i_block[13]指向一个"二级间接块",该块中存储的是一级间接块的地址,适合大文件(1×(4KB/4B)×(4KB/4B)×4KB=4GB); - 1个三级间接块 :
i_block[14]指向一个"三级间接块",该块中存储的是二级间接块的地址,适合超大文件(1×(4KB/4B)³×4KB=4TB)。
这种设计兼顾了小文件的访问效率和大文件的存储需求。
五、目录与路径解析
在Ext文件系统中,"目录"也是一种文件,其核心作用是建立"文件名"与"inode号"的映射关系。
5.1 目录的本质
- 目录是特殊文件:目录的inode存储其属性(权限、大小等),目录的数据块存储该目录下所有文件/子目录的"文件名+inode号"映射关系;
- 映射关系示例 :目录
/home/lym的数据块中存储着类似("test.cpp", 527892)的键值对; .和..的本质 :.是当前目录的硬链接,指向目录自身的inode;..是父目录的硬链接,指向父目录的inode。
通过自定义程序可读取目录的映射关系:
cpp
#include <stdio.h>
#include <dirent.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "用法: %s <目录路径>\n", argv[0]);
exit(1);
}
DIR *dir = opendir(argv[1]);
if (!dir) { perror("opendir"); exit(1); }
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue;
printf("文件名: %s, inode号: %lu\n", entry->d_name, (unsigned long)entry->d_ino);
}
closedir(dir);
return 0;
}

5.2 路径解析过程
访问文件时,操作系统需要通过"路径"逐层解析,找到文件的inode:
-
绝对路径解析 (如
/home/lym/test/test.cpp):- 从根目录(
/)开始,根目录的inode号固定(通常为2),读取根目录的数据块,找到home对应的inode号; - 访问
home目录的inode,找到其数据块,读取lym对应的inode号; - 访问
lym目录的inode,找到其数据块,读取test对应的inode号; - 访问
test目录的inode,找到其数据块,读取test.cpp对应的inode号; - 通过
test.cpp的inode号找到其inode和数据块,完成访问。
- 从根目录(
-
相对路径解析 (如
test/test.cpp):- 从当前工作目录(进程的CWD)开始,后续步骤与绝对路径一致。
5.3 路径缓存(dentry)
如果每次访问文件都从根目录解析路径,效率就太低了,Linux内核通过dentry(目录项)结构体缓存路径信息:
- dentry结构:存储文件名、对应的inode指针、父dentry指针、子dentry链表等;
- 缓存机制:内核将已解析的路径存储为dentry树,再次访问同一文件时,直接从dentry树中查找,无需访问磁盘;
- 淘汰策略 :dentry树中的节点通过LRU(最近最少使用)策略淘汰,避免占用过多内存。

六、分区挂载
我们已经能够根据inode号在指定分区找文件了,但是分区写入文件系统后,无法直接使用,需要和指定的目录关联,进行挂载才能使用 。
分区挂载就像是给房子分配房间并安装门牌的过程。硬盘先被划分成多个分区(房间),每个分区格式化成特定的文件系统(房间装修风格),然后通过挂载操作将这些分区关联到目录树的某个空目录(挂载点),就像给每个房间装上标有具体地址的门牌。这样,当用户访问 /home 目录时,实际上可能是在访问一个独立的硬盘分区,整个Linux系统通过这种机制将多个物理存储设备无缝整合成统一的目录树结构供用户使用。
七、软硬链接原理与实践
7.1 硬链接(Hard Link)
- 定义:硬链接是给文件的inode创建一个新的"文件名映射",多个硬链接指向同一个inode;
- 创建命令 :
ln 源文件 硬链接文件; - 核心特性 :
- 硬链接与源文件的inode号相同,属于同一个文件;
- 硬链接数记录在inode的
i_links_count字段,创建硬链接时该字段+1,删除时-1(为0时才释放inode和数据块); - 不能跨分区创建(inode号仅在分区内唯一);
- 不能给目录创建硬链接(避免目录树循环)。
示例操作:

两个文件inode号相同,硬链接数为2。
7.2 软链接(Symbolic Link)
- 定义:软链接是一个独立的文件(有自己的inode),其数据块中存储的是源文件的路径(相当于"快捷方式");
- 创建命令 :
ln -s 源文件 软链接文件; - 核心特性 :
- 软链接有自己的inode号,与源文件是两个独立文件;
- 软链接的权限为
lrwxrwxrwx(l表示链接文件),权限不影响访问(实际权限由源文件决定); - 可以跨分区创建(存储的是路径,与分区无关);
- 可以给目录创建软链接;
- 源文件删除后,软链接会失效(变成"死链接")。
示例操作:

inode号与源文件不同,箭头指向源文件路径。
7.3 软硬链接核心区别
| 特性 | 硬链接 | 软链接 |
|---|---|---|
| inode号 | 与源文件相同 | 与源文件不同 |
| 独立性 | 不是独立文件,是inode的别名 | 是独立文件,存储源文件路径 |
| 跨分区 | 不支持 | 支持 |
| 目录支持 | 不支持 | 支持 |
| 源文件删除影响 | 无影响(硬链接数-1) | 软链接失效(死链接) |
| 权限 | 与源文件相同 | 固定为lrwxrwxrwx(实际权限看源文件) |
| 用途 | 文件备份、防止误删 | 快捷方式、跨分区访问、目录链接 |
八、总结
Ext系列文件系统的核心设计围绕"高效管理磁盘空间"展开,其本质是通过块组、inode、目录等结构,将底层复杂的磁盘硬件抽象为用户可理解的"文件"概念。关键点:
- 磁盘层面:扇区是物理最小单位,LBA寻址是线性地址,解决了CHS寻址的局限性;
- 文件系统层面:块是存取最小单位,inode存储属性,数据块存储内容,目录建立文件名与inode的映射;
- Ext结构层面:块组设计分散管理压力,超级块和位图确保空间分配与回收的高效性;
- 链接层面:硬链接共享inode,软链接独立存储路径,满足不同的文件共享需求。