FAT32文件系统

  

这是一个FAT32文件系统,FAT1=FAT2,每一个簇占一项,内容是下一个簇号,如果是某一个文件的最后一个簇,那么内容为FFFFFF0F;

淡绿色的里面就是目录和文件了。

  这些用来存放所有文件和文件夹的“簇”占据着硬盘大部分的空间。簇是从2号开始的,所以没有0号和1号簇。如果你需要访问特定的簇,你需要用以下这条公式吧簇号(cluster number)转换为IDE设备的LBA地址:

  通常,簇的大小最少为4K(8个扇区),8K,16K和32K的簇很少使用。一些新版本的Microsoft Windows系统允许使用更 大的簇,而处于对效率的考虑,扇区(簇?)的大小都是512字节的倍数。Microsoft指出,FAT32描述的文件系统最大的簇大小为32K。

 

 

现在只要我们知道文件在哪里……

刚开始时,你只知道第一个簇和根目录(Root directory)的地址。读取目录将可以知道其他文件和目录的名字和起始簇在哪里。很重要的一点是: 目录仅仅告诉你怎么找到文件和子目录的起始的簇在哪里 。 你还需要从目录中获取诸如文件长度、修改时间、文件属性等其他种类的信息。但是目录只会告诉你文件在哪里。要得到起始簇以外的信息,你需要用到FAT(文件分配表)。但首先你需要找到这些文件是从哪里开始的。

 

在这节里面,我们只会简短地看看目录,知道哪些是找到文件所必须的。然后我们将看看怎么通过文件分配表(FAT)来找到剩下的文件。最后我们将来回头看看关于目录结构的细节。

目录数据被组织成32个字节的记录。这很好,因为每一个扇区刚好可以保存16条记录,没有记录会卡在扇区与扇区中间。这里有四种32个字节的目录记录:

  1. 短文件名的普通记录 - 属性是普通
  2. 长文件名文本 - 属性含有全部的4个字节
  3. 未使用 - 第一个字节为0xE5
  4. 目录结尾 - 第一个字节为0x00

未使用的目录记录可能是被删除的文件的记录,它的第一个字节被0xE5覆盖掉,当有新文件被创建时就可以重新使用这条记录。目录的最后是一条开头第一个字节为0的记录。所有其他的记录都是以非0开头的,所以可以很容易的察觉到你什么时候到达了目录的结尾。

 

属性字(Attrib byte)通过6bits来决定,具体如下表所示。大多数程序框架都是通过检查属性字来决定这32个字节是一般目录记 录还是长文件名数据,以及决定他是一个普通文件还是子目录。长文件名记录会把最后4位置为1。普通的文件很少会把这最后四个位全部置为1。

 

剩下的区域就相对简单和直接。开头11字节是短文件名(旧8.3格式-old 8.3 format)。扩展功能允许使用其后面的3个字节。 如果文件名的长度小于8字节,剩下的字节就会用0x20填充。起始簇号码被分为两个16位来储存,以及最后4个字节用来储存文件的大小。这两者的储存都是 通过字节来存取,低位在前,高位在后。起始簇号码告诉我们文件的数据从硬盘的哪里开始,文件大小告诉我们这个文件有多长。由于硬盘的实际空间都是通过整数 个簇来分配的,所以文件大小会让你知道其后的多少个簇存放着文件的数据。

 

文件分配表(File Allocation Table) - 连成链的簇

目录的入口告诉你文件或子目录的起始簇在硬盘的什么地方,然后就理所当然的从卷ID中的根目录中找到了第一个簇。对于小文件和目录 (大小在一个簇以内),你能从文件分配表(FAT)得到的信息只是:这个文件不占用更多的簇。要访问剩下超过一个簇的文件时,你就需要使用文件分配表 (FAT)。FAT32这个名字所代表的含义是表格中每一个入口(entry)都是32位的。在FAT16和FAT12中,入口时16和12位的。 FAT16和FAT12的工作方式与FAT32相同(只是令人讨厌的是12位的入口经常对齐不了扇区的边界,但是16和32位的入口是不会超出扇区边界 的)。我们将只介绍FAT32。

文件分配表是一个很大的32位整数序列。这个序列中的每一个入口(32位)在序列中的位置对应簇的号码,而每个入口中的内容储存着的 是该文件下一个簇的位置。文件分配表的目的就是在你知道目前簇的位置时,告诉你下一个簇的位置在哪里。每一个扇区中包含有128个这种32位的整数,所以 可以相对简单地知道下一个簇的位置。当前所在的入口中,第7到31位告诉你下一个入口在FAT中的那个扇区,剩下的0到6位告诉你下一个入口是这个扇区中 128个入口的哪一个(如果所有位都置为1,说明这是文件的结尾)。

这是一个虚拟的例子,里面有三个小文件和根目录,他们都分布在第一个簇的附近(下图中,文件需要的所有簇号码画在FAT图的旁边)。 注意到,下面这个根目录占用了5个簇,但是却悲剧的仅仅含有三个文件。这里只是想展示一下怎么样链式的寻找到簇。但是值得注意的是,如果是小的根目录(只 占一个簇),表中第2个入口中的内容将是“FFFFFFFF”(在卷ID中包含了根目录簇的首地址),而不是通过“00000009”号到达其他的簇。然 而,当根目录有很多文件的情况下,根目录会占用几个簇,但是这几个簇很少会连在一起,毕竟在你存入更多的文件之前,这个根目录还是一个只占用一个簇的小目 录。那么在记住这些要点后,我们来看看简单的例子:

图7: FAT32扇区,根目录和三个文件的簇链

在这个例子中,通过卷ID的信息我们知道根目录从2号簇开始。在FAT的第2个位置里面的数字式9,所以下一个是9号簇。像这样,簇 A,B和11保存了根目录剩下的数据。在位置11的数字“FFFFFFFF”表示这里是根目录的最后一个簇。但是你的代码可能不会去读地11个位置,因为 你将会找到一个目录结束标记(end-of-directory marker)(开头32个字节全为0)。就这样,这个文件系统就含有大小为一个簇的小 型根目录,而且在读取目录时不需要使用FAT,因为只有一个簇。但是如果你在这个簇中没有发现目录结束标记,那么就必须通过FAT来寻找剩下的簇了。

同样的,这里显示了三个文件。在所有情况下,FAT都没有指出哪个是文件的第一个簇,所以必须从目录中提取文件的首地址,然后通过 FAT来访问剩下的簇。分配给文件的簇的总字节数必须大于目录记录中文件大小区域指出的文件大小。除非文件的大小不是簇的整数倍的话,否则最后一个簇的末 尾就会有一部分未使用的空间。文件大小是0的文件将不会分配簇,在目录记录中的簇数量应该为0。文件大小只占用一个簇的文件在FAT中对应簇的内容为 “FFFFFFFF”表示已经到文件末尾。

便捷提示: 一个能使代码尽可能简单的方法是是的根目录非常小(少量文件,只用8.3短文件名),避免出现子目录,以及在电脑上运行整理磁盘碎片程序。这样,根目录能 在一个簇中找到,然后每个文件占据着地址连续的簇。虽然这种实现的功能非常有限,但是这样你就可以不使用文件分配表了。

更具Microsoft的描述,簇号码其实只占28位,高四位是保留的。你可以在把这些保留的位清零。同样的,文件结束号码 (end-of-file number)实际上是所有比0xFFFFFFF8大的数,但是实际上通常使用0xFFFFFFFF。FAT中为全0的标记是 自由的位置。同样的,请记住在内存中簇号码是先储存他们的低字节(低地址对低地址)(图7中使用的格式是为了便于我们阅读,但是他们实际上市先储存低字节 的-stored LSB first)。所以其实在内存中,FAT中二号簇实际上在二进制编码器中会写成“90000000”,低字节在前。

好消息是,对于固件开发者来说使用FAT是很简单的。但是,FAT的简单导致的大量计算往往也是起作为一个通用文件系统的弱点。例 如,为了向文件增加数据,文件系统必须读便整个簇链。在文件中任意位置中定位也需要大量的读取FAT。处于比较的目的,Unix文件系统使用树状结构。其 中的簇(也叫作“区块”)会拥有完整的区块列表(在unix哲学中被叫做“inode”)或者拥有另一个包含着inode的区块。制这种方式下,定位一个 硬盘中的任意一个区块只需要读取1,2或者3个inode。FAT的另外可以通过缓存来缓解的缺点在于,它数据的物理分布会集中在磁盘的“开头”,而不是 分布式储存的。Unix基于inode(inode-based)的文件系统会把inode区块均匀地分布在数据区块之间,然后把数据区块定位在 inode区块附近。

posted @ 2016-04-09 21:26  cancanw  阅读(1147)  评论(0编辑  收藏  举报