FAT12文件系统
FAT12(File Allocation Table 12)是一种简单的文件系统,主要用于早期的软盘和小容量存储设备。它的设计简单、易于实现,因此在嵌入式系统和早期的操作系统中广泛使用。FAT12 是 FAT 文件系统家族中的一员,后续还有 FAT16 和 FAT32。
写在前面
由于最近一款嵌入式产品需要使用spi flash存储数据并通过外接usb接口将数据读出,故考虑将设备插入电脑识别为U盘,这就涉及到需要使用FAT12文件系统,本文将介绍其数据结构,并通过编码实现,以及在调试学习过程中遇到的问题及思考。目标达成:
1.输出引导扇区结构数据。
2.输出根目录区数据结构。
3.通过嵌入式软件通过FAT12文件系统存入一个txt文件,并通过电脑读取出来。
FAT12文件系统结构
FAT12特点
- 12 位 FAT 表项:每个 FAT 表项占 12 位(1.5 字节),用于表示簇的状态。
- 小容量支持:FAT12 适用于小容量存储设备(如软盘),通常支持的最大容量为 32MB。
- 简单结构:FAT12 的结构简单,易于实现和调试。
- 兼容性:FAT12 被大多数操作系统支持,具有良好的兼容性。
FAT12文件系统结构
FAT12文件系统分为5个区,引导扇区中记录了整个文件系统的基础信息。FAT1表与FAT2表完全一致,属于相互备份的关系,里面存储了簇号,与数据区存在特殊的关系,后续会详细介绍。根目录区记录了文件系统内所有存储的文件信息,包括文件名、簇号、属性、时间等等。数据区不言而喻,是存储文件主体内容的地方。
序号 | 扇区位置 | 扇区个数 | 备注 |
---|---|---|---|
01 | 0 | 1 | 引导扇区 |
02 | 1 | 1 | FAT1表 |
03 | 2 | 1 | FAT2表 |
04 | 3 | 4 | 根目录区 |
05 | 7 | 1 | 数据区 |
引导扇区结构
标识 | 偏移量 | 类型 | 大小 | 默认值 | 描述 |
---|---|---|---|---|---|
JMP instruction | 0 | db | 3 | EB 3C 90 | 跳转指令 |
OEM | 3 | db | 8 | MSDOS5.0 | OEM字符串,必须为 8 个字符,不足会以空格填充 |
Bytes per sector | B | dw | 2 | 4,096 | 每个扇区字节数 |
Sectors per cluster | D | db | 1 | 2 | 每簇占用的扇区数 |
Reserved sectors | E | dw | 2 | 1 | 保留扇区 |
Number of FATs | 10 | db | 1 | 2 | FAT 表的数量(通常为 2,用于冗余)。 |
Root entries | 11 | dw | 2 | 512 | 根目录可容纳的目录项数 |
Sectors (under 32 MB) | 13 | dw | 2 | 4096 | 逻辑扇区总数 |
Media descriptor (hex) | 15 | db | 1 | F8 | 媒体描述符 |
Sectors per FAT | 16 | dw | 2 | 1 | 每个 FAT 表占用的扇区数。 |
Sectors per track | 18 | dw | 2 | 1 | 每磁道的扇区数。 |
Heads | 1A | dw | 2 | 1 | 磁头数。 |
Hidden sectors | 1C | dd | 4 | 0 | 隐藏扇区数(通常为 0)。 |
Sectors (over 32 MB) | 20 | dd | 4 | 0 | 逻辑扇区总数(容量高于32MB看这里) |
BIOS drive (hex, HD=8x) | 24 | db | 1 | 80 | BIOS驱动器号 |
(Unused) | 25 | db | 1 | 0 | 未使用 |
Ext. boot signature (29h) | 26 | db | 1 | 29 | 扩展引导标志 |
Volume serial number (decimal) | 27 | dd | 4 | 4110327770 | 卷序列号 |
Volume serial number (hex) | 27 | dd | 4 | DA 9F FE F4 | 卷序列号 |
Volume label | 2B | db | 11 | NO NAME | 卷标,必须为11个字符,不足会以空格填充 |
File system | 36 | db | 8 | FAT12 | 文件系统类型,必须是8个字符,不足以空格填充 |
BOOT_Code | 3E | db | 448 | - | 引导代码 |
Signature (55 AA) | 1FE | db | 2 | 55 AA | 系统引导标识,引导扇区结束标识 |
媒体描述符常见值
值(十六进制) | 描述 |
---|---|
0xF0 | 3.5 英寸高密度软盘(1.44MB) |
0xF8 | 硬盘 |
0xF9 | 3.5 英寸双密度软盘(720KB) |
0xFA | 5.25 英寸单密度软盘(320KB) |
0xFB | 3.5 英寸高密度软盘(1.2MB) |
0xFC | 5.25 英寸单密度软盘(180KB) |
0xFD | 5.25 英寸双密度软盘(360KB) |
0xFE | 5.25 英寸单密度软盘(160KB) |
0xFF | 5.25 英寸双密度软盘(320KB) |
FAT表结构
FAT 项 | 可取值 | 描述 |
---|---|---|
0 | BPB_Media | 磁盘标识字,低字节需与 BPB_Media 数值保持一致, F8 |
1 | FFFh | 表示第一个簇已占用 |
2 ~ N | 000h | 空闲簇 |
001h | 保留簇 | |
002h~FEFh | 已用簇,指向下一个簇 | |
FF0h~FF6h | 保留簇 | |
FF7h | 坏簇 | |
FF8h~FFFh | 文件的最后一个簇,结束簇 |
FAT表采用链表结构,12bit为一个信息单元,
例如FAT1中的数据为: F8 FF FF FF FF FF FF 7F 00 FF FF FF; 第5簇的数据为 007,表示第五簇数据区末尾指向第七簇,连接起来才是完整数据,第六簇为FFF表示只用了一簇数据区,第七簇FFF表示文件最后一个簇。
根目录区
名称 | 偏移 | 长度 | 描述 |
---|---|---|---|
DIR_Name | 0x00 | 11 | 文件名 8B,扩展名 3B |
DIR_Attr | 0x0B | 1 | 文件属性 |
保留 | 0x0C | 10 | 保留位 |
DIR_WrtTime | 0x16 | 2 | 最后一次写入时间 |
DIR_WrtDate | 0x18 | 2 | 最后一次写入日期 |
DIR_FstCtus | 0x1A | 2 | 起始簇号 |
DIR_FileSize | 0x1C | 4 | 文件大小 |
数据区
1.引导扇区中的关键信息
- 在计算数据扇区之前,需要从引导扇区中获取以下关键信息:
- 每扇区字节数(Bytes Per Sector):4096
- 每簇扇区数(Sectors Per Cluster):1
- 保留扇区数(Reserved Sectors):1
- FAT 表数量(Number of FATs):2
- 每个 FAT 表占用的扇区数(Sectors Per FAT)。
- 根目录条目数(Root Entries):根目录的最大条目数。
- 根目录占用的扇区数:可以通过根目录条目数计算。
2.计算根目录占用的扇区数
根目录的扇区数可以通过以下公式计算:
根目录扇区数
=
根目录条目数
×
32
每扇区字节数
根目录扇区数 = \frac{根目录条目数×32}{每扇区字节数}
根目录扇区数=每扇区字节数根目录条目数×32
- 每个根目录条目占 32 字节。
- 结果向上取整。
3.计算数据区的起始扇区
数据区的起始扇区可以通过以下公式计算:
数据区起始扇区
=
保留扇区数
+
(
F
A
T
表数量
×
每个
F
A
T
表占用的扇区数)
+
根目录扇区数
数据区起始扇区 = 保留扇区数+(FAT表数量×每个FAT表占用的扇区数)+根目录扇区数
数据区起始扇区=保留扇区数+(FAT表数量×每个FAT表占用的扇区数)+根目录扇区数
4.计算文件对应的数据扇区
文件的起始簇号可以从根目录条目中获取。数据扇区的计算公式如下:
数据扇区
=
数据区起始扇区
+
(簇号
−
2
)
×
每簇扇区数
数据扇区 = 数据区起始扇区+(簇号-2)×每簇扇区数
数据扇区=数据区起始扇区+(簇号−2)×每簇扇区数
- 簇号:文件的起始簇号(从根目录条目中获取)。
- 每簇扇区数:文件系统的最小分配单位。
- 减去 2:因为簇号从 2 开始(簇号 0 和 1 保留)。
软件实现
软件就通过SPI驱动FLASH,读出引导扇区数据,并根据引导扇区数据结构进行解析,然后可以得到FAT1、FAT2、根目录的起始扇区,读取FAT1可以得知数据区分布簇,读取根目录可以知道文件目录,得到每个文件存储的起始簇,然后通过写flash,可以往对应文件写数据;
注意事项:往文件写数据需要确保三个地方正确,数据区要正确,根目录对应文件size也需要改写,涉及到文件需要增加簇时,FAT1表也需要进行修改,FAT2表就是FAT1表的备份,需要同时修改。