参考:文件分配、inode、链接与典型 FS 速查
基于通用操作系统概念 · 核于 2026-08
速查
- 文件:磁盘块的命名集合 = 数据(字节流)+ 属性(元数据:名称/大小/时间/权限/inode 号)。
- 目录:特殊文件,内容是文件名 → inode的目录项(dentry)表;名与 inode 分离是硬链接基础。
- 分配方式:连续(快但外部碎片)、链接(无碎片但不支持随机访问)、索引/inode(支持随机访问 + 无碎片,主流)。
- inode:UNIX/Linux 索引节点,存属性 + 12 直接 + 1 一级 + 1 二级 + 1 三级间接指针;小文件直接指针够用,大文件逐级间接。
- 软链接:独立 inode,内容是目标路径字符串,可跨 FS/链接目录,目标删则悬空失效。
- 硬链接:新目录项指向同一 inode,inode 链接计数 +1,不能跨 FS/不能链接目录,删原文件数据仍在。
- 路径:绝对(从
/起算,唯一)vs 相对(从 cwd 起算,./..)。 - 空闲管理:位图(主流,找连续块快)、空闲链表、块计数。
- 典型 FS:EXT4(日志+extents,Linux)、NTFS(MFT,Windows)、APFS(COW+快照,Apple)。
- 访问方式:顺序(磁带/流)、随机(
lseek定位,需分配方式支持)、索引(按键查,DB)。
一、文件分配方式对比
| 维度 | 连续分配 | 链接分配 | 索引分配(inode) |
|---|---|---|---|
| 存储 | 首块号 + 块数 | 首块号 + 块内下一块指针 | inode 索引表(块指针数组) |
| 顺序访问 | ✅ 最快 | ✅ 较快(磁头乱跳慢) | ✅ 快 |
| 随机访问 | ✅ 最快(偏移算) | ❌ 不支持(必须顺序走) | ✅ 支持(查索引) |
| 碎片 | ❌ 外部碎片严重 | ✅ 无 | ✅ 无 |
| 增长 | ❌ 难(尾部占则挪文件) | ✅ 易(接链尾) | ✅ 易(加指针) |
| 可靠性 | 一般 | ❌ 断链丢数据 | ✅ 较好 |
| 代表 | CD-ROM、Swap | FAT(变种)、早期 Unix | EXT4、UFS、NTFS |
一句话:通用磁盘 FS 几乎都用索引分配——因为现代应用强依赖随机访问,链接分配"只能顺序读"无法接受。
二、inode 结构与寻址
以块大小 4KB、指针 4B 计(一个间接块装 4KB/4B = 1024 个指针):
inode(定长,通常 256B)
┌──────────────────────────────┐
│ 属性: 大小 / 权限 / 属主 / 时间 │
├──────────────────────────────┤
│ 0~11: 直接块指针(12 个) │ ──▶ 数据块 0~11
│ 12: 一级间接指针 │ ──▶ 间接块(1024指针) ──▶ 数据块
│ 13: 二级间接指针 │ ──▶ 间接块 ──▶ 间接块 ──▶ 数据块
│ 14: 三级间接指针 │ ──▶ 三层间接 ──▶ 数据块
└──────────────────────────────┘| 指针类型 | 个数 | 覆盖块数 | 覆盖容量(4KB 块) |
|---|---|---|---|
| 直接 | 12 | 12 | 48 KB |
| 一级间接 | 1 | 1024 | 4 MB |
| 二级间接 | 1 | 1024² | ≈ 4 GB |
| 三级间接 | 1 | 1024³ | ≈ 4 TB |
设计精髓:多数文件很小(< 48KB),12 个直接指针就够,访问只需读一次 inode——小文件高效;大文件逐级启用间接指针,时间换空间。
三、软链接 vs 硬链接
| 维度 | 硬链接(hard link) | 软链接(symbolic link) |
|---|---|---|
| 本质 | 新目录项指向同一 inode | 独立 inode,内容是目标路径字符串 |
| inode | 与原文件相同 | 独立 |
| 跨文件系统 | ❌ 不能(inode 号仅本 FS) | ✅ 可以(存路径) |
| 链接目录 | ❌ 禁止(怕成环) | ✅ 可以 |
| 目标删除后 | 数据仍在(计数>0 不释放) | ❌ 变悬空链接失效 |
| 额外开销 | 几乎无(一个目录项) | 一个 inode + 路径解析 |
| 创建命令 | ln 源 链接 | ln -s 源 链接 |
| 类比 | 同一文件多一个名字 | 快捷方式(指向路径) |
链接计数(link count):inode 中记录有多少目录项指向它。rm = unlink 删目录项使计数 -1,减到 0 才释放数据块。
bash
$ ln a.txt hard # 硬链接:hard 与 a.txt 同 inode
$ ln -s a.txt soft # 软链接:soft 是独立 inode,存 "a.txt"
$ ls -li
1234 -rw-r--r-- 2 alice a.txt # inode 1234, link=2
1234 -rw-r--r-- 2 alice hard # 同 inode 1234
5678 lrwxrwxrwx 1 alice soft -> a.txt # 独立 inode 5678
$ rm a.txt # 删 a.txt,hard 仍可读(inode 1234 计数=1)
$ cat soft # 失败:a.txt 已删,软链接悬空四、空闲空间管理
| 方法 | 说明 | 优缺点 | 代表 |
|---|---|---|---|
| 位图(bitmap) | 每位对应一块,1 占用/0 空闲 | ✅ 找连续块快、占空间小、易一致性校验 | EXT4、NTFS、APFS |
| 空闲链表 | 空闲块串成链表 | ✅ 省空间;❌ 找块慢、不支持连续分配 | 早期 Unix |
| 块计数 | 连续空闲段记(起块+数量) | ✅ 大段连续高效;❌ 碎片多时退化 | CISAM |
位图是现代 FS 主流:df 报的已用/可用空间来自位图统计;分配大文件时扫描位图找连续的 0。
五、典型文件系统对比
| FS | 平台 | 核心特性 | 适用 |
|---|---|---|---|
| EXT4 | Linux | 日志(断电可回放)、extents(连续区段,大文件高效)、兼容 ext2/3 | Linux 服务器/桌面 |
| NTFS | Windows | **MFT(主文件表)**统一存元数据、日志、ACL、压缩/加密/稀疏文件 | Windows 主流 |
| APFS | Apple | **写时复制(COW)**支持快照/克隆、SSD 友好(TRIM)、空间共享、强加密 | macOS/iOS(2017+) |
| XFS | Linux | 高并发、大文件高效、在线整理 | 高性能存储 |
| ZFS/Btrfs | 服务器 | COW、校验和、快照、RAID-Z | 数据完整性要求高 |
| FAT32 | 跨平台(U 盘) | FAT 表变种、兼容性最好、不支持大文件(>4GB) | U 盘/嵌入式 |
- 日志(journal):写文件先记"要改哪些元数据"到日志区,再改实际数据——断电后回放日志恢复一致性,避免全盘
fsck。 - 写时复制(COW):修改文件不覆盖原块,而是写新块改指针——快照/克隆几乎零成本,断电后原数据完好。
- extents:连续分配的区段(起块+长度)替代逐块指针,大文件只需少量 extent 描述,元数据小、分配快。
六、易错点清单
- "硬链接复制了一份文件":错。硬链接只是多一个目录项指向同一 inode,没有数据复制(
ls -li看 inode 号相同)。du对硬链接只计一次。 - "软链接和硬链接一样":错。软链接是独立 inode 存路径(快捷方式),硬链接是同一 inode 的多个名字——本质不同。
- "硬链接能跨分区":错。硬链接存 inode 号,inode 号只在同一 FS/分区内有效,故不能跨文件系统;软链接存路径可跨。
- "硬链接可以链接目录":错。一般禁止,否则
find/rm -r会成环死循环。软链接可以链接目录。 - "删了原文件,硬链接就读不到了":错。硬链接与原文件等价,删原文件只是目录项计数 -1,数据仍在(只要还有硬链接)。软链接才会悬空失效。
- "链接分配支持随机访问":错。链接分配(块链表)要读第 N 块必须从头走 N 次,不支持随机访问——这是它被通用 FS 淘汰的主因。FAT 是变种(表进内存)才缓解。
- "inode 里存文件名":错。文件名存在目录项里,inode 存属性 + 块指针。所以同一文件可以有多名字(硬链接)。
- "inode 占的空间算在文件里":错。inode 是 FS 元数据,独立占用空间(inode 表区),
df -i看 inode 使用率。小文件多会耗尽 inode(即使磁盘块还有空)。 - "日志让文件系统更快":错。日志是为了一致性(断电不损坏),代价是额外写放大(多写日志),吞吐可能略降。
- "APFS 的快照要复制数据":错。APFS 用写时复制,快照只记指针、几乎零成本、即时完成。
七、进阶方向(链接其他叶)
- 内存管理基础 —— 文件缓存与页缓存的协作
- 设备与 I/O 管理 —— 文件 IO 如何落到磁盘调度
- 操作系统概述 —— 文件系统在 OS 四大功能中的位置