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-20190910
1组  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进制)。

这些信息,都蛮奇怪了。不过经常接触嵌入式,也就不奇怪了。

经典FAT文件系统格式详解相关推荐

  1. 文件系统的详解与常见文件系统模式比较

    目录 1. 文件系统的详解 2. 常见的文件系统比较 2.1 Windows下的文件系统 2.1.1 FAT16文件系统 2.1.2 FAT32文件系统 2.1.3 FAT64文件系统(exFAT文件 ...

  2. Java字节码(.class文件)格式详解(一)

    原文链接:http://www.blogjava.net/DLevin/archive/2011/09/05/358033.html 小介:去年在读<深入解析JVM>的时候写的,记得当时还 ...

  3. php serialize取值,PHP 序列化(serialize)格式详解

    PHP 序列化(serialize)格式详解(转) 1.前言 PHP (从 PHP 3.05 开始)为保存对象提供了一组序列化和反序列化的函数:serialize.unserialize.不过在 PH ...

  4. php serialize mysql_php 序列化(serialize)格式详解

    1.前言 PHP (从 PHP 3.05 开始)为保存对象提供了一组序列化和反序列化的函数:serialize.unserialize.不过在 PHP 手册中对这两个函数的说明仅限于如何使用,而对序列 ...

  5. 三维重建:PNG格式详解-与LibPNG使用

    PNG图像包含了骨骼信息,左边的图像比右边的大几十K,包含了骨骼信息:        PNG格式详解:https://blog.mythsman.com/post/5d2d62b4a2005d7404 ...

  6. 4-4:TCP协议之TCP头部格式详解

    文章目录 一:TCP头部格式详解 (1)4位首部长度 (2)序列号和确认应答号 A:可靠性问题 B:32位序号和确认号 (3)窗口大小 (4)标志位 (5)紧急指针 A:带外数据(out_of _ba ...

  7. PHP 序列化(serialize)格式详解

      1.前言 PHP (从 PHP 3.05 开始)为保存对象提供了一组序列化和反序列化的函数:serialize.unserialize.不过在 PHP 手册中对这两个函数的说明仅限于如何使用,而对 ...

  8. 安卓camera2 API获取YUV420_888格式详解

    安卓音视频开发中的一个环节是摄像头采集数据,Android平台上摄像头采集的API有两套,camera1和camera2.本文主要讲的是camera2这套API采集数据,并指明YUV420_888格式 ...

  9. Gerber 格式详解

    Gerber 格式详解 gerber中文 gerber,gerber 文件:590m.com/f/25127180-487459253-79168e(访问密码:551685) 以下内容无关: ---- ...

  10. BMP格式详解<转>

    BMP格式详解 BMP文件格式详解(BMP file format) BMP文件格式,又称为Bitmap(位图)或是DIB(Device-Independent Device,设备无关位图),是Win ...

最新文章

  1. VB6 通过winsock控件数组实现客户端和服务器多对一通信
  2. 17章 SPI控制器(XIlinx ZYNQ-7000 SOC UG-585文档)
  3. hibernate的lazy的使用
  4. centOS7挂在windows移动硬盘方法
  5. 易语言神经网络验证码识别_递归神经网络 GRU+CTC+CNN 教会验证码识别
  6. django-自定义转换器-实操案例
  7. php软件开发--nodejs
  8. [DOTween]使用过程中的一些注意事项记录
  9. Weld(CDI)教程
  10. 抖音c语言表白编码,抖音微信表白代码大全 微信表白代码总汇
  11. manul_css.css:1 Failed to load resource: the server responded with a status of 404 ()
  12. linux ps 2鼠标驱动,佳能 PS/2 TrackPoint 驱动程序下载-更新佳能软件(鼠标)
  13. ATtiny85简单引脚配置
  14. 使用Teamviewer实现远程控制安卓设备的实现过程记录
  15. 不同终端通信用c语言实现,采用蓝牙技术的北斗终端通信模块的设计
  16. Excel合并计算完成多表格数据汇总求和
  17. 2022ICPC预选赛 A Yet Another Remainder(数学)(构造)
  18. IDEA 显示Cannot resolve plugin org.apache.maven.pluginsmaven-site-plugin3.3
  19. MATLAB 绘制时钟(同步当前时间)
  20. SpringBoot中重试框架——Spring-retry与Guava-Retry

热门文章

  1. 第5节:Tableau堆积图 | 价格等级堆积柱形图
  2. ArcCatalog基础操作
  3. 怎么查看ubuntu虚拟机ip地址?
  4. 怎么查看虚拟机上的ip地址?
  5. 解决cmd中tomcat中文乱码问题
  6. 嵌入式软件设计(freertos使用)
  7. Warshall算法求传递闭包
  8. Scala 安装教程
  9. 数据透视表练习表格_将高级电子表格导出与PHP结合起来以创建数据透视表
  10. 阵列天线方向图乘积定理的Python实现