logo资料库

FAT32简单教材.pdf

第1页 / 共19页
第2页 / 共19页
第3页 / 共19页
第4页 / 共19页
第5页 / 共19页
第6页 / 共19页
第7页 / 共19页
第8页 / 共19页
资料共19页,剩余部分请下载后查看
FAT32 文件系统的存储机制及其在单片机上的实现 FAT32 文件系统您一定不会陌生,最多看到它是在 windows 操作系统里,但在一些嵌 入式产品(如手机、MP3、MP4 等)中,也能看到它的身影。从某种意义上来讲,FAT32 文件系统是非常成功的,使我们可以脱离底层储存设备驱动,更为方便高效地组织数据。给 单片机系统中的大容量存储器(如 SD 卡、CF 卡、硬盘等)配以 FAT32 文件系统,将是非 常有意义的(如创建的数据文件可以在 windows 等操作系统中直接读取等)。 FAT32 本身是比较复杂的,对其进行讲解的最好方法就是实际演练。笔者手里持有一张 刚以 FAT32 格式化的 SD 卡,我们就围绕它来讲解 FAT32 的实现机理。 FAT32 分为几个区域,这里将用实例的方法对它们的结构与在文件存储中的功能进行详 细的剖析。 1、 实例说明 此实例首先在一张空的 SD 卡(已被格式化为 FAT32 格式)上创建一个文本文 件,并在其中输入 20 个字符。再将它插入到单片机系统中,实现对这个文件的读 取,将文件内容输出在调试终端上。 2、 实现过程 1) 格式化与创建文件 Windows 上的磁盘格式化与文件创建就不用多说了。如下图: 2)DBR(DOS BOOT RECORD 操作系统引导记录区) DBR 是我们进军 FAT32 的首道防线。其实 DBR 中的 BPB 部分才是这一 区域的核心部分(第 12~90 字节为 BPB),只有深入详实的理解了 BPB 的意义, 才能够更好的实现和操控 FAT32。关于 DBR 在 FAT32 中的地位就不多说了,
以下面实际的 DBR 内 图所示: 上面的数据看起来杂乱不堪,无从下手,其实对我们有用的数据只不过90 个字节(如图中彩色线标记的字节)。仅仅是这 90 个字节就可以告诉我们关于 磁盘的很多信息,比如每扇区字节数、每簇扇区数、磁道扇区数等等。对于这 些信息的读取,只要遵循 DBR 中的字段定义即可。(比如图中紫色字段的两个 字节表示这张磁盘的每一个扇区有 512 个字节,具体的计算方法见下文) 字段定义如下表(BPB 后面的 422 个字节对我们的意义不大,表中省略): 字段名称 jmpBoot OEMName 长度 含义 3 8 跳转指令 这是一个字符串,标识了格式化该分 区的操作系统的名称和版本号 BytesPerSec SecPerClus RsvdSecCnt NumFATs RootEntCnt 2 1 2 1 2 每扇区字节数 每簇扇区数 保留扇区数目 此卷中 FAT 表数 FAT32 为 0 偏移量 0 3 11 13 14 16 17
FAT32 为 0 存储介质 FAT32 为 0 磁道扇区数 磁头数 FAT 区前隐扇区数 该卷总扇区数 FAT 表扇区数 FAT32 特有 FAT32 特有 根目录簇号 文件系统信息 通常为 6 扩展用 - - - - - - TotSec16 Media FATSz16 SecPerTrk NumHeads HiddSec TotSec32 FATSz32 ExtFlags FSVer RootClus FSInfo BkBootSec Reserved DrvNum Reserved1 BootSig VolID FilSysType FilSysType1 2 1 2 2 2 4 4 4 2 2 4 2 2 12 1 1 1 4 11 8 DBR 的实现代码: struct FAT32_DBR { 19 21 22 24 26 28 32 36 40 42 44 48 50 52 64 65 66 67 71 82 unsigned char BS_jmpBoot[3]; //跳转指令 unsigned char BS_OEMName[8]; // unsigned char BPB_BytesPerSec[2];//每扇区字节数 unsigned char BPB_SecPerClus[1]; //每簇扇区数 unsigned char BPB_RsvdSecCnt[2]; //保留扇区数目 unsigned char BPB_NumFATs[1]; //此卷中 FAT 表数 unsigned char BPB_RootEntCnt[2]; //FAT32 为 0 unsigned char BPB_TotSec16[2]; //FAT32 为 0 unsigned char BPB_Media[1]; //存储介质 unsigned char BPB_FATSz16[2]; //FAT32 为 0 unsigned char BPB_SecPerTrk[2]; //磁道扇区数 unsigned char BPB_NumHeads[2]; //磁头数 offset: 0 offset: 3 offset:11 offset:13 offset:14 offset:16 offset:17 offset:19 offset:21 offset:22 offset:24 offset:26 unsigned char BPB_HiddSec[4]; //FAT 区前隐扇区数 offset:28
unsigned char BPB_TotSec32[4]; //该卷总扇区数 offset:32 unsigned char BPB_FATSz32[4]; //一个 FAT 表扇区数 offset:36 unsigned char BPB_ExtFlags[2]; //FAT32 特有 unsigned char BPB_FSVer[2]; //FAT32 特有 unsigned char BPB_RootClus[4]; //根目录簇号 offset:40 offset:42 offset:44 unsigned char FSInfo[2]; //保留扇区 FSINFO 扇区数 offset:48 unsigned char BPB_BkBootSec[2]; //通常为 6 unsigned char BPB_Reserved[12]; //扩展用 unsigned char BS_DrvNum[1]; // unsigned char BS_Reserved1[1]; unsigned char BS_BootSig[1]; unsigned char BS_VolID[4]; // // // unsigned char BS_FilSysType[11]; // unsigned char BS_FilSysType1[8]; //"FAT32 " }; offset:50 offset:52 offset:64 offset:65 offset:66 offset:67 offset:71 offset:82 在程序中我们采用以上的结构体指针对扇区数据指针进行转化,就可以直接读 取数据中的某一字段,如要读取 BPB_BytesPerSec,可以这样来作: ((struct FAT32_DBR *)pSector)­> BPB_BytesPerSec 用如上语句就可以得到这一字段的首地址。 心细的读者可能会发现读回来的字节拼在一起,与实际的数据并不吻合。例 如 BPB_BytesPerSec 读出来的内容是“00 02”,在程序中我们把 00 作为 int 型变 量的高字节,把 02 作为其低字节,那么这个变量的值为 2,而实际的 SD 卡里的 扇区大小为 512 个字节,这 512 与 2 之间相去甚远。是什么造成这种现象的呢? 这就是大端模式与小端模式在作怪。上面我们合成int 型变量的方法(00 为 高字节,02 为低字节)为小端模式。而如果我们改用大端模式来进行合成的话, 结果就会不同:将 02 作高字节,而把 00 作低字节,变量值就成了 0x0200(十进 制的 512),这样就和实际数据吻合了。可见 FAT32 中字节的排布是采用小端模式 的。在我们程序中需要将它转为大端模式的表达方式。在笔者的程序有这样一个 函数 lb2bb,专门垃圾将小端模式转为大端模式,程序如下:
unsigned long lb2bb(unsigned char *dat,unsigned char len) //小端转为大端 { } unsigned long temp=0; unsigned long fact=1; unsigned char i=0; for(i=0;i
当然也可以用零散的变量来存储参数,但用结构体更方便管理,也会使程序 更为整洁。FAT32 的初始化将向结构中装入参数,实现如下: void FAT32_Init(struct FAT32_Init_Arg *arg) { struct FAT32_BPB *bpb=(struct FAT32_BPB *)(FAT32_Buffer); //将数据缓冲区指针转为 struct FAT32_BPB 型指针 arg­>BPB_Sector_No =FAT32_FindBPB(); //FAT32_FindBPB()可以返回 BPB 所在的扇区号 arg­>Total_Size =FAT32_Get_Total_Size(); //FAT32_Get_Total_Size()可以返回磁盘的总容量,单位是兆 arg­>FATsectors =lb2bb((bpb­>BPB_FATSz32) //装入 FAT 表占用的扇区数到 FATsectors 中 arg­>FirstDirClust =lb2bb((bpb­>BPB_RootClus) ,4); ,4); //装入根目录簇号到 FirstDirClust 中 arg­>BytesPerSector =lb2bb((bpb­>BPB_BytesPerSec),2); //装入每扇区字节数到 BytesPerSector 中 arg­>SectorsPerClust =lb2bb((bpb­>BPB_SecPerClus) ,1); //装入每簇扇区数到 SectorsPerClust 中 arg­>FirstFATSector=lb2bb((bpb­>BPB_RsvdSecCnt) ,2)+arg­ >BPB_Sector_No; //装入第一个 FAT 表扇区号到 FirstFATSector 中 arg­>RootDirCount =lb2bb((bpb­>BPB_RootEntCnt) ,2); //装入根目录项数到 RootDirCount 中 arg­>RootDirSectors =(arg­>RootDirCount)*32>>9; //装入根目录占用的扇区数到 RootDirSectors 中 arg­>FirstDirSector=(arg­>FirstFATSector)+(bpb­ >BPB_NumFATs[0])*(arg­>FATsectors); //装入第一个目录扇区到 FirstDirSector 中 arg­>FirstDataSector =(arg­>FirstDirSector)+(arg­>RootDirSectors); //装入第一个数据扇区到 FirstDataSector 中
} 3)FAT(文件分配表) FAT 表是 FAT32 文件系统中用于磁盘数据(文件)索引和定位引进的一种 链式结构。可以说 FAT 表是 FAT32 文件系统最有特色的一部分,它的链式存储 机制也是 FAT32 的精华所在,也正因为有了它才使得数据的存储可以不连续, 使磁盘的功能发挥得更为出色。 FAT 表到底在什么地方?它到底是什么样子的呢? 从第一步从 BPB 中提取参数中的 FirstFATSector 就可以知道 FAT 表所在的 扇区号。其实每一个 FAT 表都有另一个与它一模一样的 FAT 存在,并且这两个 FAT 表是同步的,也就是说对一个 FAT 表的操作,同样地,也应该在另一个 FAT 表进行相同的操作,时刻保证它们内容的一致。这样是为了安全起见,当一个 FAT 因为一些原因而遭到破坏的时候,可以从另一个FAT 表进行恢复。 FAT 表的内容如下图所示: 上图就是一个实际的 FAT 表。前 8 个字节“F8 FF FF 0F FF FF FF FF”为 FAT32 的 FAT 表头标记,用以表示此处是 FAT 表的开始。后面的数据每四个 字节为一个簇项(从第 2 簇开始),用以标记此簇的下一个簇号。 拿我们创建的那个叫 TEST.TXT(大小为 20 个字节)的文件来说,如果这 个文件的开始簇为第 2 簇的话,那么就到 FAT 表里来查找,看文件是否有下 一个簇(如果文件大小大于一个簇的容量,必须会有数据存储到下一个簇,但 下一个簇与上一个簇不一定是连续的),可以看到“簇 2”的内容为“FF FF FF 0F”,这样的标记就说明这个文件到第 2 簇就已经结束了,没有后继的簇,即 此文件的大小是小于一个簇的容量的。
上面讲了很多,都是围绕簇这样一个词来讲的,簇又是什么?为什么要将 它引入到 FAT32 里来呢? 磁盘上最小可寻址存储单元称为扇区,通常每个扇区为512 个字节。由于 多数文件比扇区大得多,因此如果对一个文件分配最小的存储空间,将使存储 器能存储更多数据,这个最小存储空间即称为簇。根据存储设备(磁盘、闪卡 和硬盘)的容量,簇的大小可以不同以使存储空间得到最有效的应用。在早期 的 360KB 磁盘上,簇大小为 2 个扇区(1,024 字节);第一批的 10MB 硬盘的簇 大小增加到 8 个扇区(4,096 字节);现在的小型闪存设备上的典型簇大小是8KB 或 16KB。2GB 以上的硬盘驱动器有 32KB 的簇。如果对于容量大的存储定义 了比较小的簇的话,就会使 FAT 表的体积很大,从而造成数据的冗余和效率 的下降。 需要指出的是,簇作为 FAT32 进行数据存储的最小单位,内部扇区是不 能进一步细分的,即使一个文件的数据写到一个簇中后,簇中还有容量的剩余 (里部扇区没有写满),哪怕这个簇只写了一个字节,其它文件的数据也是不 能接在后面继续数据的,而只能另外找没有被占用的簇。 我们按照初始化参数表中的 SectorsPerClust 可以知道一个簇中的扇区 数,笔者的 SD 卡实测簇大小为 4 个扇区,按照上面的说法,TEST.TXT 这样 一个只有 20 个字节的文件,也会占用一个簇的容量,让我们在Windows 里看 看它的实际占用空间的情况。如下图:
分享到:
收藏