
1、机械磁盘物理结构
机械硬盘 (HDD) 是计算机里唯一的机械设备,属于块外设。特点:大容量、廉价、速度慢,有盘片、磁头、主轴电机。




1.1 磁盘核心部件
- 盘片 Platter:圆形磁盘薄片,两面都可以存储数据,涂上磁性介质。一张盘片有上下2 个盘面。
- 主轴马达 Spindle:带动所有盘片高速旋转(7200 转 / 10000 转)。
- 磁头 Head:读写数据,一个盘面对应一个磁头,所有磁头固定在磁头臂,磁头是共进退的!(重点!!柱面概念的来源)
- 磁头臂 / 传动臂:移动磁头,径向移动切换磁道。
- 永磁铁:驱动磁头臂摆动。







📌重点记忆:所有磁头一起移动,不能单独移动某一个磁头,这是柱面概念的根本来源。
1.2 磁盘存储单元:磁道、柱面、扇区
磁盘容量计算公式:
\\(磁盘容量=磁头数 × 柱面数 × 每磁道扇区数 × 每扇区字节数\\)
1.3 CHS 寻址(柱面‑磁头‑扇区)
早期磁盘使用 CHS 三维坐标定位扇区:C(柱面号) H(磁头号) S(扇区号)
- 柱面 C:从 0 开始编号
- 磁头 H:从 0 开始编号
- 扇区 S:从 1 开始编号(不是 0!坑点)
CHS 寻址硬件限制: 8bit 存磁头、10bit 存柱面、6bit 存扇区。 最大支持容量:256 * 1024 *63 *512B ≈8GB,硬盘越来越大,CHS 不够用,于是诞生 LBA 线性寻址。
1.4 LBA 逻辑块地址(线性地址)
把磁盘所有扇区,全部展开成一维数组,数组下标就是 LBA 地址,LBA 从 0 开始计数。操作系统只和 LBA 打交道,不再关心物理的柱面磁头。
CHS ↔ LBA 的转换由磁盘固件(磁盘硬件自己)完成,上层操作系统完全不用管物理 CHS。
CHS 转 LBA 公式
\\(LBA = C ×(磁头数 ×每磁道扇区数)+ H ×每磁道扇区数 + (S-1)\\)
S 要减 1,因为扇区 S 从 1 开始,LBA 从 0 开始。
LBA 转 CHS 公式
单个柱面总扇区 = 磁头数 * 每磁道扇区数
C = LBA // 单个柱面总扇区
H = (LBA % 单个柱面总扇区) // 每磁道扇区数
S = (LBA % 每磁道扇区数) + 1
实操:查看磁盘扇区信息
fdisk -l
输出片段示例:
Disk /dev/vda: 42.9 GB, 42949672960 bytes, 83886080 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
/dev/vda1 2048 83875364 41936658+ 83 Linux
- 83886080 sectors:磁盘总扇区数量
- 每个扇区 512 字节;分区起始 LBA=2048。
💡知识点:扇区是硬件最小读写单元,但操作系统不会按 512 字节读写,太慢!操作系统引入块 (block)。
2、块 (block):操作系统文件存取最小单位

扇区:硬件磁盘最小读写单位(512 字节) 块 block:操作系统文件存取最小单位!格式化的时候确定大小,不可修改。
最常见:4KB 块 = 8 个 512 字节扇区。操作系统一次性读取 8 个连续扇区作为一个块,减少 IO 次数,提升性能。
关系:
- 块号 = LBA / 8
- LBA = 块号 * 8 + 块内扇区偏移
实操 stat 命令看块大小
stat main.c
输出示例:
File: 'main.c'
Size: 488 Blocks:8 IO Block:4096 regular file
Device: fd01h/64769d Inode:1052007 Links:1
Access: (0664/-rw-rw-r–) Uid:(1000/whb) Gid:(1000/whb)
Access: 2024-10-25 22:15:52.909616443 +0800
Modify: 2024-10-17 19:06:11.139423737 +0800
Change: 2024-10-17 19:06:11.139423737 +0800
- IO Block:4096:块大小 4KB
- Blocks:8:该文件占用 8 个 512 字节扇区,合计 4KB。哪怕文件只有 488 字节,也要占一整个块。
小文件浪费磁盘空间根源:块是分配最小单位,不足一个块也要占用完整块。
3、分区是什么?
磁盘可以切割成多个分区,Windows 的 C 盘 D 盘就是分区。
- 早期分区以柱面为最小划分单元,给定起始柱面、结束柱面。
- Linux 下分区对应设备文件:/dev/vda1、/dev/sda2。
- 分区只是划分磁盘空间,分区之后不能直接存文件!必须格式化(写入文件系统)。
划重点:分区只是空间切割;格式化是往分区里面写入管理数据(超级块、位图、inode 表等)。
4、inode(索引节点)核心概念

Linux:文件属性和文件内容分开存储!
- 文件内容:存放在 Data Block 数据块
- 文件元属性(权限、属主、大小、时间、数据块指针)存放在 inode 索引节点。
4.1 inode 里面保存什么?
ext2_inode 结构体关键字段:
struct ext2_inode {
__le16 i_mode; // 文件权限、文件类型
__le16 i_uid; // 用户id
__le32 i_size; // 文件字节大小
__le32 i_atime; // access访问时间
__le32 i_ctime; // change属性修改时间
__le32 i_mtime; // modify内容修改时间
__le32 i_dtime; // 删除时间
__le16 i_gid; // 组id
__le16 i_links_count; // 硬链接计数
__le32 i_blocks; // 文件占用块数量
__le32 i_block[15]; // 15个块指针!直接/间接块
};
📌非常重要细节:
实操 ls -li 查看 inode 号
ls -li
输出:
1052669 -rw-rw-r– 1 whb whb 225 Oct 17 19:09 test.txt
1052007 -rw-rw-r– 1 whb whb 488 Oct 17 19:06 main.c
第一列数字就是 inode 编号。
inode 中 15 个块指针 i_block [15]
#define EXT2_NDIR_BLOCKS 12 // 12个直接块
#define EXT2_IND_BLOCK 12 // 一级间接块
#define EXT2_DIND_BLOCK 13 // 二级间接块
#define EXT2_TIND_BLOCK 14 // 三级间接块
#define EXT2_N_BLOCKS 15
- 12 个直接块:直接存数据块编号,小文件全部用直接块,访问速度最快。
- 一级间接块:块里面不存文件数据,存一堆数据块编号指针。
- 二级间接块:指针指向一级间接块列表。
- 三级间接块:指针指向二级间接块列表。
这样设计,让 ext2 既可以高效处理小文件,又支持超大文件。
touch 创建新文件发生了什么?
⚠️目录本身也是文件!目录的内容就是一张表:文件名 <—-> inode编号。 文件名只保存在目录文件里面,inode 完全不知道自己叫什么名字!
验证:读取目录内容,打印文件名和 inode
保存为readdir.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <directory>\\n", argv[0]);
exit(EXIT_FAILURE);
}
DIR *dir = opendir(argv[1]);
if (!dir) {
perror("opendir");
exit(EXIT_FAILURE);
}
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
printf("Filename: %-20s Inode: %lu\\n", entry->d_name, (unsigned long)entry->d_ino);
}
closedir(dir);
return 0;
}
编译运行:
gcc readdir.c -o readdir
./readdir ./
输出每个文件名对应的 inode 号,和ls -li第一列完全对应。
这就实锤:目录文件存储的就是文件名和 inode 映射关系!
上篇小结





