4. FAT16文件系统原理:MBR与DBR结构解析、FAT表与簇链管理、根目录区与数据区布局

各位同学,咱们今天来啃一块硬骨头——FAT16文件系统。说实话,我当年刚接触USB Mass Storage设备时,第一个拦路虎就是这玩意儿。你想想看,一个U盘插到电脑上,操作系统怎么知道里面存了哪些文件?文件又存在哪个扇区?这一切的起点,就是MBR和DBR。

4.1 MBR与DBR:存储设备的“户口本”

MBR(Master Boot Record)位于整个存储设备的0号扇区。它就像设备的户口本,记录了分区表信息。我调试过一个U盘,插上后电脑死活不认盘,用WinHex一看,MBR的结束标志55 AA被改成了55 00——就这一个字节,整个设备就废了。

MBR结构(512字节)

  • 0x000 - 0x1BD:引导代码(446字节)—— 对于数据盘,这部分通常为空
  • 0x1BE - 0x1FD:分区表(64字节,4个分区表项,每项16字节)
  • 0x1FE - 0x1FF:结束标志 0x55 0xAA

每个分区表项16字节,结构如下:

偏移 长度 含义
0x00 1 引导标志(0x80=可引导,0x00=不可引导)
0x01 3 CHS起始地址
0x04 1 分区类型(0x06=FAT16,0x0B=FAT32,0x07=NTFS)
0x05 3 CHS结束地址
0x08 4 LBA起始扇区号
0x0C 4 分区总扇区数

DBR(DOS Boot Record)则是每个分区的第一个扇区。它记录了该分区的文件系统参数。我习惯用BPB(BIOS Parameter Block)来称呼它,因为这才是核心。

避坑指南:我曾经在调试一个4GB的U盘时,发现分区类型写的是0x06(FAT16),但FAT16最大只能管理2GB。结果Windows能识别,Linux却报错。后来改成0x0E(FAT16 LBA)才解决。记住:容量超过2GB一定要用FAT32或exFAT。

4.2 FAT表与簇链管理:文件存储的“导航图”

FAT(File Allocation Table)表,说白了就是一张“簇的导航图”。每个文件占用的簇,通过FAT表项链接成一个链条。我刚开始做USB MSC设备时,总觉得FAT表很神秘,后来自己写了一个FAT表解析工具,才彻底搞明白。

FAT16的每个表项占16位(2字节)。表项的值含义如下:

表项值 含义
0x0000 空闲簇
0x0002 - 0xFFEF 已分配簇,值指向下一个簇号
0xFFF0 - 0xFFF6 保留簇
0xFFF7 坏簇
0xFFF8 - 0xFFFF 文件结束簇(EOF)

举个例子:假设文件A占用簇2、5、8。那么FAT表项2的值是5,表项5的值是8,表项8的值是0xFFFF。读取时,从簇2开始,顺着FAT表一路找到簇8,遇到0xFFFF就停止。

注意:FAT表通常有两份副本(FAT1和FAT2)。FAT2是备份,当FAT1损坏时可以用来恢复。我遇到过U盘FAT1被病毒破坏,靠FAT2恢复了全部数据。所以,千万别把FAT2的空间挪作他用。

4.3 根目录区与数据区布局

根目录区紧跟在FAT2之后。FAT16的根目录位置和大小是固定的,这一点和FAT32不同。根目录区由32字节的目录项组成,每个目录项对应一个文件或子目录。

目录项结构如下:

偏移 长度 含义
0x00 8 文件名(不足8字节用空格填充)
0x08 3 扩展名
0x0B 1 属性(0x01=只读,0x02=隐藏,0x04=系统,0x08=卷标,0x10=子目录,0x20=归档)
0x0C 10 保留/时间/日期(NT专用)
0x16 2 最后修改时间
0x18 2 最后修改日期
0x1A 2 起始簇号
0x1C 4 文件大小(字节)

数据区则是实际存储文件内容的地方。从根目录区结束后的第一个簇开始,按簇分配。

整个FAT16分区的布局如下:

  1. DBR扇区:0号扇区(相对于分区起始)
  2. 保留扇区:通常只有DBR一个扇区,但也可以更多
  3. FAT1:第一个FAT表
  4. FAT2:第二个FAT表(备份)
  5. 根目录区:固定大小,通常32个扇区(可容纳512个目录项)
  6. 数据区:从根目录区结束后的第一个簇开始

这里有个关键点:簇号从2开始。簇0和簇1在FAT表中是保留的,不用于数据存储。所以数据区的第一个簇(簇2)对应的是根目录区之后的第一个扇区。

个人经验:我在调试一个USB读卡器时,发现SD卡格式化后根目录区大小不是标准的32扇区。后来一查,是格式化工具把BPB中的“根目录项数”字段改成了1024。结果根目录区占了64个扇区,导致数据区偏移计算全错。所以,永远不要假设根目录区是32扇区,一定要从BPB中读取。

下面这张图展示了FAT16分区的完整布局:

FAT16分区布局结构图 DBR (引导扇区) — 0号扇区 保留扇区(通常仅DBR,可扩展) FAT1 (文件分配表 — 主表) FAT2 (文件分配表 — 备份表) 根目录区(固定大小,通常32扇区) 数据区(簇2开始) 簇2 → 簇3 → 簇4 → ... → 簇N 注意:簇号从2开始,簇0和簇1在FAT表中保留

嗯,这张图把整个FAT16分区的层次关系讲得很清楚了。从上到下依次是:DBR、保留扇区、FAT1、FAT2、根目录区、数据区。每个区域都有明确的边界和功能。

4.4 实战:如何计算文件在数据区的位置

假设我们要读取一个文件,它的起始簇号是100。怎么找到它在数据区的实际扇区号?

公式很简单:

数据区起始扇区号 = 保留扇区数 + (FAT表个数 × 每个FAT表的扇区数) + 根目录区扇区数
文件数据扇区号 = 数据区起始扇区号 + (簇号 - 2) × 每簇扇区数

举个例子:

  • 保留扇区数 = 1
  • FAT表个数 = 2
  • 每个FAT表扇区数 = 256
  • 根目录区扇区数 = 32
  • 每簇扇区数 = 8
  • 起始簇号 = 100

计算过程:

数据区起始扇区号 = 1 + (2 × 256) + 32 = 545
文件数据扇区号 = 545 + (100 - 2) × 8 = 545 + 784 = 1329

所以,文件数据从第1329号扇区开始。这个计算在USB MSC设备的固件开发中非常常用,我建议你把它背下来。

我曾经踩过的坑:在计算根目录区扇区数时,直接用BPB中的“根目录项数”除以16(每个扇区16个目录项)。但有些格式化工具会把根目录项数设成非16的倍数,导致除不尽。正确的做法是:根目录区扇区数 = (根目录项数 × 32 + 511) / 512,向上取整。

好了,FAT16的核心原理就这些。MBR告诉你分区在哪,DBR告诉你文件系统参数,FAT表告诉你簇的链接关系,根目录区告诉你文件名和起始簇号,数据区存着真正的文件内容。把这几个概念串起来,你就能理解整个FAT16的运作机制了。