经典FAT文件系统格式详解 | 您所在的位置:网站首页 › fat中文谐音怎么读写 › 经典FAT文件系统格式详解 |
FAT/FAT32曾经是windows下主流文件格式,虽然FAT已经这么多年了,也见识到一些缺点,但熟悉FAT,还是对文件系统认识有很大帮助。
一般来说,需要具备一些前期知识: 1. 文件存在flash或硬盘里,还是一个个字节进行存储的,存储介子本身不负责具体内容。如果要对硬盘的数据进行识别,必须需要一定格式,还需要一个驱动程序进行识别。 2. 文件格式最主要作用:格式化管理,快速查找文件
还有几个知识点: 扇区:一般为512,最小分割单位,但不是最小管理单位。 簇:管理最小单位,一般是由多个扇区组成,有2、4、8、16、32或64几种情况。如果=16,即8K=16*512,也就是说一个文件最小也得占8K空间 DBR及保留扇区(FAT16不存在)、文件分配表区(FAT1、FAT2)、数据区(DATA区)。 反过来说,一个文件至少占一族,或多簇。最后一簇往往是未存满的,这样肯定会带来空间的浪费。(但也没太好办法,毕竟是要快速查找文件的) 当然,这个可以根据实际情况来设定,毕竟应用场景不一样。
FAT16的根目录区只有32个扇区,计算一下,每个扇区512字节,共32个扇区,而每个文件名至少要占用32个字节(后面会介绍),很显然,根目录最多只能放512个文件了。 FAT16 这里存在致命缺陷的: 例如:我们的文件是存在根目录的,那么最多也只能存放512个文件(假设文件名又很长的话,这个数量就更小了) FAT32对这方面进行了优化,可以支持更多的文件数量,但格式变得复杂了,查找时也是先从前面扇区往后跳(会根据目录最后指向下一个扇区地址),所以时间上也浪费很多,搜索起来非常慢 FAT大体格式: 这里:FAT表有两个,一般FAT2为镜像。FAT表非常重要,一般如果文件名乱码,或一下子消失了,往往是FAT表坏掉了。 MBR: Main Boot Record 主引导记录区 DBR:Dos Boot Record 操作系统引导记录区
以下,是我对FAT16格式注解: FAT格式:(FAT16)
FAT32格式: FAT表格式: FAT表之后就是目录区:
目录区是由一个个目录项构成,类似于FAT表。其中每一个目录项占用32个字节,可以是代表长文件名目录项、文件目录项、子目录项等。对于短文件名格式的目录项,其参数的含义如表1所示(不会画这种表,从别处引用了一个)[1]: 通过这些信息,也基本知道文件信息,比如创建信息,修改信息等 也可以看到有两个限制: 1. 文件名的长度为8字节,那长一点文件名怎么办? 2.扩展名为3字节,这个虽然是限制,但实际还可以接受。 其实,这个历史原因导致的,原先Dos系统下就根本没考虑中文这种场景(现在windows系统都是基于DOS发展起来) 那长一点文件名怎么办? 先看下FAT32对长文件名的处理: 表15 FAT32长文件目录项32个字节的表示定义 字节偏移 (16进制) 字节数 定义 0x0 1 属性字节位意义 7 保留未用 6 1表示长文件最后一个目录项 5 保留未用 4 顺序号数值 3 2 1 0 0x1~0xA 10 长文件名unicode码① 0xB 1 长文件名目录项标志,取值0FH 0xC 1 系统保留 0xD 1 校验值(根据短文件名计算得出) 0xE~0x19 12 长文件名unicode码② 0x1A~0x1B 2 文件起始簇号(目前常置0) 0x1C~0x1F 4 长文件名unicode码③ 0x00~0x00:1 个字节,长文件名目录项的序列号,一个文件的第一个目录项序列号为 1,然后依次递增。如果是该文件的最后一个长文件名目录项,则将该目录项的序号与 0x40 进行“或(OR)运算”的结果写入该位置。如果该长文件名目录项对应的文件或子目录被删除,则将该字节设置成删除标志0xE5。0x01~0x0A:10 个字节,长文件名的第 1~5 个字符。长文件名使用 Unicode 码,每个字符需要两个字节的空间。如果文件名结束但还有未使用的字节,则会在文件名后先填充两个字节的“00”,然后开始使用 0xFF 填充。0x0B~0x0B:1 个字节,长目录项的属性标志,一定是 0x0F。0x0C~0x0C:保留。0x0D~0x0D:1 个字节,校验和。如果一个文件的长文件名需要几个长文件名目录项进行存储,则这些长文件名目录项具有相同的校验和。0x0E~0x19:12 个字节,文件名的第 6~11 个字符,未使用的字节用 0xFF 填充。0x1A~0x1B:2 个字节,保留。0x1C~0x1F:4 个字节,文件名的第 12~13 个字符,未使用的字节用 0xFF 填充。 总共这个也是32字节(跟短文件名一致),那么如何区别?关键看0B位置,如果是=0F,那么就是长文件名。 长文件名的实现有赖于目录项偏移为0xB的属性字节,当此字节的属性为:只读、隐藏、系统、卷标,即其值为0FH时,DOS和WIN32会认为其不合法而忽略其存在。这正是长文件名存在的依据。 长文件名中的字符采用unicode形式编码(一个巨大的进步哦),每个字符占据2字节的空间。 从上表中可以获得文件名长度:0x01~0x0A:10字节; + 0x0E~0x19 12字节; + 0x1C~0x1F 4字节; 总共26字节,即13个字符!(被拆七零八落,有点可怜)
那么怎么表达一个长文件名呢?从以上两个表来看,都无法做到兼容 解决办法:短文件名(32)+长文件名(32).... 规则: (1)、取长文件名的前6个字符(第1个字符改成0x01)加上"~1"形成短文件名,扩展名不变。(放在第1组32字节) (2)、如果已存在这个文件名,则符号"~"后的数字递增,直到5。(如果是看二进制是可以看到这些奇怪的名称,有时候在文件fat表破坏掉之后也会出来~1这样的奇怪文件) (3)、如果文件名中"~"后面的数字达到5,则短文件名只使用长文件名的前两个字母。通过数学操纵长文件名的剩余字母生成短文件名的后四个字母,然后加后缀"~1"直到最后(如果有必要,或是其他数字以避免重复的文件名)。 (4)、如果存在老OS或程序无法读取的字符,换以"_" (5)、从第2组32字节开始,以13字节为一组,分别表示的文件名。如果存在多组,则以倒叙的办法表示,前面的是文件名末尾部分。 有点懵,举个例子说明下更清晰: 假设一个文件,文件名为 ZHUANCHU-12345678-20190910H095830.bin 文件名实际长度=33,那么/13,需要三组长文件名来表示。 3组H095830 不足部分用FF替代2组5678-201909101组 ZHUANCHU-1234这个格式参考上面的 《长文件名格式》
那么FAT格式文件名大概是这样的: 其中0F表示长文件名的标志。 96表示短文件名校验值(三组都一样) 红色框起来的是文件名的分组。根据长文件名格式定义,被拆分成不同地方。
好了。我们再回到文章前面的,计算下,如果我们的文件名大概都是这样的:“ZHUANCHU-12345678-20190910H095830.bin”,只是数字不一样 那么FAT根目录下最多可以存放多少个这样的文件?(假设全部文件容量要大大小于存储空间) 一个文件名占 3长+1短,共4个坑。总共512个坑,那最多只能放128这样的文件! 这也是,为什么我们存储空间是够的,但存储是失败的原因~~
so,根目录的文件名可不是随意的,建议小于8字节最佳!(这样只要一组短文件名就可以了)~~
搞定了文件名的含义,我们再来看看文件内容存放(实际就是关注起始地址) 文件起始地址 文件起始地址(文件内容) = (保留扇区数 + FAT表扇区数 * FAT表个数(2) + (文件起始簇号-2)*每簇扇区数)*每扇区字节数
文件起始簇号:(在短文件名里)高在前 实际计算:感觉文件起始簇号不用-2,OK? 例如下列文件 实验1: 数据区偏移地址:ADDR=(8+256*2+(0x09C3 – 2)*16)* 512= 20,721,664=0x013C3000 根目录有 32*512=0x4000 (固定32个扇区表示目录,内容区) 实际地址=0x013C3000+0x4000=0x013C7000
实验2: 假设 rec/文件夹有一个文件为:888888.txt 里面内容为 “jjw” 来分析下,子文件/rec下一个888888.txt文件(实际跟放在哪里没有关系) 数据区偏移地址:ADDR=(8+256*2+(0x09C4 – 2)*16)* 512= 20,729,856= 0x013C5000 实际地址=0x013C5000+0x4000=0x013C9000 再来说下,时间信息格式: 日期时间,可以表示创建信息,修改信息,访问信息 格式都一样,这里以创建信息举例: 0x0E~0x0F 文件创建时间 0x785C = (0111100001011100)(2进制) 即为 15:02:57(注释1) 0x10~0x11 文件创建日期 0x4508 = (0100010100001000)(2进制) 即为 2014/8/8(注释2) 注释1:01111 000010 11100 1)这里高5位代表小时,由于2^5 = 32,足够表示24小时,这边01111(2进制) = 15(10进制); 2)次6位代表分钟,同理2^6 = 64,足够表示60分钟,这边000010(2进制) = 2; 3)低5位表示秒的1/2, 计算结果需要加上毫秒位上的进位,这边11100(2进制) = 28(10进制),所以秒数 = 28*2 = 56,再加上毫秒上的进位1所以结果为57。
注释2:0100010 1000 01000 1)这里高7位代表从1980年开始的年数,笔者计算了下可以到2108年,总之还有90多年可以使用,这边0100010(2进制) = 34,所以年份 = 1980+34 = 2014; 2)次4位代表月份,2^4=16,可以表示12个月份,这边 1000(2进制) = 8(10进制); 3)低5位代表日期,2^5 = 32,可以表示28~31天,这边 01000(2进制) = 8(10进制)。
这些信息,都蛮奇怪了。不过经常接触嵌入式,也就不奇怪了。 |
CopyRight 2018-2019 实验室设备网 版权所有 |