入门:文件抽象、目录与路径
基于通用操作系统概念 · 核于 2026-08
速查
- 文件(File):磁盘上一组相关数据的命名集合——文件系统把无序的磁盘块包装成有名字、可读写、可保护的逻辑单元,是"长期存储信息"的最小抽象(关机不丢)。
- 文件 = 数据 + 属性:数据是字节流(UNIX 哲学"一切皆文件",二进制/文本一视同仁);属性/元数据包括名称、类型、大小、位置、创建/修改时间、属主、权限位(rwx)、inode 号等。
- 文件类型:UNIX 用首字节魔数(magic number,如 ELF/脚本
#!)识别,不靠扩展名;Windows 则重度依赖扩展名(.exe/.txt/.jpg)决定打开程序。 - 目录(Directory/Folder):特殊的文件,内容是一组目录项(目录项),每项映射文件名 → inode/位置。目录把命名空间组织成层次,便于分类与查找。
- 目录结构演进:单级(全部文件同一目录,早期 CP/M)→ 树形(UNIX/Linux/Windows 主流,根
/下层层嵌套)→ 无环图(允许一个文件多个路径,软/硬链接)。 - 绝对路径:从根目录
/起算的完整路径(如/home/alice/a.txt),与当前目录无关,唯一确定。 - 相对路径:从当前工作目录(cwd)起算(如
../bob/b.txt),依赖当前所在目录,简短但易变。 - 特殊目录名:
.= 当前目录,..= 上一级目录,~= 用户家目录(shell 约定,非 OS 语义)。 - 文件操作(系统调用):
create/open(打开,返回 fd)/read/write/lseek(定位,随机访问)/close/unlink(删除硬链接)/truncate/rename——本质是对目录项 + inode 的增删改查。 - 访问方式:顺序访问(磁带模型,从头到尾读,最常见)、随机/直接访问(按偏移
lseek定位,数据库/索引依赖)、索引访问(按键查,需 FS/DB 支持如 B+ 树)。 - 文件系统职责:命名(路径树)、分配(数据存哪些块)、空闲管理(哪些块可用)、目录管理(名→位置映射)、保护(权限)、一致性(断电不损坏)。
- 挂载(mount):把一个文件系统的根接到主文件系统树的某个目录(挂载点),形成统一的命名空间——Linux 的"单一全局树"由挂载拼装而成。
- 进阶顺序:文件分配与索引(数据怎么存 + inode)→ 目录结构与链接(软硬链接 + 空闲管理)→ 参考。
一、文件抽象:从磁盘块到命名文件
磁盘的物理接口极其朴素——按扇区(sector,通常 512B)/块(block,通常 4KB)读写。如果让用户直接操作"读第 12345 号块",系统几乎无法使用。文件系统的核心抽象是文件:把一个逻辑文件的内容映射到若干物理块上,并提供名字供人引用。
用户/程序视角 文件系统内部
┌─────────────────┐ ┌──────────────────────┐
│ a.txt 3.2KB │ ──映射──▶ │ inode #1234 │
│ (命名 + 字节) │ │ 指针 → 块 200 │
└─────────────────┘ │ 指针 → 块 201 │
│ (2 个 4KB 块) │
└──────────────────────┘- 一切皆文件(UNIX 哲学):普通文件、目录、设备(
/dev/sda)、管道(/dev/fd)、套接字都用统一的open/read/write接口,降低心智负担。 - 文件 = 数据 + 属性:数据是字节流;属性(元数据)由文件系统单独存储(inode 中)。
ls -l看到的权限、属主、大小、时间全是属性。
二、文件属性与类型
属性(元数据) 是文件"除了内容之外的信息",存储在 inode 或目录项中:
| 属性 | 说明 | 查看 |
|---|---|---|
| 名称 | 文件名(存在目录项,非 inode) | ls |
| 类型 | 普通/目录/链接/设备/管道 | ls -l 首字符 |
| 大小 | 字节数 | ls -l |
| 时间 | atime/mtime/ctime | stat |
| 属主/组 | owner/group | ls -l |
| 权限 | rwx(属主/组/其他) | ls -l |
| inode 号 | 索引节点号 | ls -i |
| 数据块位置 | 指针(存在 inode) | debugfs |
文件类型的识别有两种风格:
- UNIX/Linux:魔数——读文件首字节判断(ELF 可执行、
#!脚本、PK zip 压缩)。扩展名只是约定,mv a.txt a仍可执行。 - Windows:扩展名——
.exe/.txt/.jpg决定关联程序。改扩展名可能改变打开方式,安全性较差(病毒靠改后缀伪装)。
特殊文件类型:目录(内容是目录项)、符号链接(内容是目标路径)、设备文件(字符设备/块设备,对应外设)、管道/套接字(用于通信)。
三、目录:命名空间与目录项
目录本身也是文件,但其数据是一张文件名 → inode的映射表,每一行叫目录项(directory entry,dentry):
目录 /home/alice 的内容(目录项表)
┌──────────────┬──────────┬────────────────┐
│ 文件名 │ inode 号 │ 其他(类型) │
├──────────────┼──────────┼────────────────┤
│ a.txt │ 1234 │ 普通文件 │
│ photos │ 5678 │ 目录 │
│ proj → ../p │ 9012 │ 符号链接 │
└──────────────┴──────────┴────────────────┘- 文件名与 inode 分离:文件名在目录项里,inode 存属性与块指针——这是硬链接存在的基础(多个文件名指向同一 inode)。
- 硬链接计数(link count):inode 中记录有多少目录项指向它,删到 0 才真正释放数据块。
目录结构的演进:
| 结构 | 说明 | 问题 |
|---|---|---|
| 单级 | 所有文件在同一目录 | 文件一多就乱,无法分类(早期 CP/M) |
| 树形 | 根 / 下层层嵌套,每个文件唯一路径 | 主流,但一个文件不能有多个路径 |
| 无环图 | 允许子目录被共享(软/硬链接) | 需防环(软链接可成环,要小心) |
四、路径:绝对与相对
路径(path) 是定位文件的字符串,由 / 分隔的目录名序列组成:
- 绝对路径:从根
/起算,如/home/alice/a.txt。唯一、与当前目录无关,适合配置文件、脚本引用。 - 相对路径:从当前工作目录(cwd,
pwd显示)起算,如photos/a.jpg或../bob/b.txt。简短但随 cwd 变化。 .与..:.是当前目录(常用于./run.sh强制执行本目录文件),..是上一级目录(cd ..返回上层)。- 路径分隔符:UNIX 用
/,Windows 用\(但现代 Windows API 也接受/)。 - 大小写:UNIX/Linux 区分大小写(
A.txt≠a.txt),Windows/macOS(默认 HFS+/APFS)大小写不敏感。
解析路径时,文件系统逐级查目录项:/home/alice/a.txt → 读根目录找 home 的 inode → 读 home 目录找 alice → 读 alice 目录找 a.txt 的 inode → 读数据块。每经过一层目录都要一次查找,所以目录层级太深会影响路径解析速度(VFS 的 dentry 缓存能缓解)。
五、文件访问方式
| 访问方式 | 说明 | 典型场景 |
|---|---|---|
| 顺序访问 | 从头到尾依次读写,最简单 | 文本流、日志、音视频流 |
| 随机/直接访问 | lseek 到任意偏移再读写 | 数据库、索引(需分配方式支持) |
| 索引访问 | 按键查记录(B+ 树) | 数据库(需 FS 或上层支持) |
随机访问是否高效取决于分配方式:连续分配最佳(直接算偏移),索引分配(inode)也支持(按间接指针定位),链接分配不支持(要顺着链表走)。这解释了为什么数据库文件必须放在支持随机访问的 FS 上。
下一步
理解了文件抽象与目录、路径后,下一步深入数据怎么存——文件分配与索引(连续/链接/索引分配的取舍、inode 的多级间接指针、随机访问的支持)。