FAT 32 文件系统学习

1、本文的目标

本文将通过实际读取一个FAT32格式的U盘来简单了解和学习FAT32文件系统的格式。虽然目前windwos操作系统的主流文件系统格式是NTFS,但是FAT32由于其兼容性原因,还是有一定的学习价值。为了能做出一个窗体程序提供直观的感觉,本文的代码采用c#编写,对应的c++代码也会附上。

2、本文目录

1、本文的目标

2、什么是FAT32

2.1 FAT32的构成

3、引导区

3.1 读取引导扇区

3.2 BPB参数

3.3 程序实现

2、什么是FAT32

FAT32是Windwos系统硬盘格式分区的一种。这种格式采用32位的文件分配表,使其对磁盘的管理能力大大增强,突破了FAT16对配一个分区的容量只有2GB的限制。虽然目前已被更优异的NTFS分区格式所取代[1]。其实说白了就是FAT表的每一项长度都是32位,所以叫做FAT32。至于每一项存放的内容是什么,下面的内容会慢慢进行分析。

  • FAT32的构成

FAT32 文件系统将逻辑盘的空间划分为三部分,依次是引导区 (BOOT区)、文件分配表区(FAT区)、数据区(DATA区)[2]。引导区和文件分配表区又合称为系统区。本文将简单学习引导区的内容,文件分配表区和数据区将在下一篇文章中学习。

3、引导区

  • 读取引导扇区

引导区从第一扇区开始,保存了每个扇区的字节数,一个簇的扇区数,FAT表的起始位置,FAT表的个数以及FAT表的扇区数等信息。之后还留有若干保留扇区。首先我们先看一下如何从一个U盘当中读取引导区(这里只读取第一个扇区,接下来的读取方法相同)。为了直接读取磁盘的逻辑扇区,我们需要用到windows api当中的几个函数,分别是CreateFile(这里用来创建磁盘的句柄),ReadFile(这里用于读取磁盘扇区)。首先来看一下这两个函数的定义:

 HANDLE WINAPI CreateFile(
_In_ LPCTSTR lpFileName, // 要打开的文件的名或设备名。
_In_ DWORD dwDesiredAccess, // 指定类型的访问对象。
_In_ DWORD dwShareMode, // 文件共享模式
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 定义了文件的安全特性
_In_ DWORD dwCreationDisposition,
_In_ DWORD dwFlagsAndAttributes,
_In_opt_ HANDLE hTemplateFile // 返回句柄
);

这个函数在msdn上可以查到,这里需要说明一下的是,dwShareMode需要指定为FILE_SHARE_WRITE才能读取扇区的数据(这里是为什么我也不太清楚为什么,希望高人指教)。dwCreationDisposition需要制定为OPEN_EXISTING ,表示文件必须已经存在,由设备提出要求。函数如执行成功,则返回文件句柄。否则返回的句柄 = INVALID_HANDLE_VALUE表示出错,会设置GetLastError。具体失败原因可以查询ErrorCode。

第二个函数是ReadFile,其定义如下:

 BOOL ReadFile(
HANDLE hFile, //文件的句柄
LPVOIDl pBuffer, //用于保存读入数据的一个缓冲区
DWORD nNumberOfBytesToRead, //要读入的字节数
LPDWORD lpNumberOfBytesRead,//指向实际读取字节数的指针
LPOVERLAPPED lpOverlapped
//如文件打开时指定了FILE_FLAG_OVERLAPPED,那么必须,用这个参 数引用一个特殊的结构。
//该结构定义了一次异步读取操作。否则,应将这个参数设为NULL
);

该函数用于读取文件,这里指的是读取U盘扇区。其中lpOverlapped设为NULL即可。需要特别注意的是,由于磁盘是以扇区为单位进行读写的,所以这里读取的字节数必须是512的倍数!其他参数注释写的很明白,这里就不再解释了。配合SetFilePointer函数可以读取指定起始位置上指定字节的数据。

首先先来看一下用c++是如何读取引导扇区的数据的。

     // 笔者的U盘盘符为G
WCHAR szDiscFile[] = _T("\\\\.\\G:");
// 打开设备句柄
HANDLE hDisc = CreateFile(szDiscFile, GENERIC_READ, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, , NULL);
if (hDisc == INVALID_HANDLE_VALUE)
{
// 打开设备失败
return ;
}
// 从第一个扇区起始位置开始读取
SetFilePointer(hDisc, , , FILE_BEGIN);
// 需要读取字节数
DWORD dwNumber2Read = ;
// 实际读取的字节数
DWORD dwRealNumber;
// 分配缓冲区
char* buffer = new char[];
bool bRet = ReadFile(hDisc, buffer, dwNumber2Read, &dwRealNumber, NULL); // 扫尾工作,释放缓冲区,关闭句柄
delete[] buffer;
CloseHandle(hDisc);

如果我们在21行处下各断点的话可以看到buffer在内存中的数据,这里为了方便,笔者直接把这512个字节的数据保存到了文件中,用二进制文件读取软件打开来看了下,部分数据如下图所示:

  • BPB参数

好了,接下来重点来了。首先,最开始的3各字节的数据分别是跳转指令与空指令,因为在汇编当中0xEB是跳转指令,0x58是跳转的地址,而0x90则是空指令。至于为什么要在这里放上一句跳转指令呢,这个还得从启动区开始讲起,为了节约篇幅,我就简单介绍一下:一般第一个扇区叫做启动区,cpu把扇区当中的数据当作指令来执行,当读取到EB 58 这个指令时,遍跳转到0x58这个地址并继续读取指令来执行,而0x58地址之后的内容通常都是载入操作系统的指令。如果希望知道详细内容的读者不妨去看一下《30天自制操作系统》这本书,第一天结尾部分有很详细的说明。总之这边的话FAT32规定这个3各字节的内容必须是EB 58 90,只要记住就行了(笑)。(如1L所说,EB 58 90 对应汇编代码即为JUMP 0x58; NOP;)。

而从0x03~0x0A这8个字节的数据表示OEM,这里即为“MSDOS5.0”。

我们把从0x000B开始的79个字节的数据叫做BPB(BIOS Paramter Block),关于BPB的详细说明请参见下表[5]

BPB参数信息
偏移量 字节数 含义
0x00B 2 每扇区字数 0x0200
0x00D 1 每簇扇区数 0x08
0x00E 2 保留扇区数 0x03F8
0x010 1 FAT个数 0x02
0x011 2 根目录项数,FAT32以突破该限制,无效  0x0000 
0x013 2 扇区总数,小于32M使用  0x0000 
0x015 1 存储介质描述负  0x0F8 
0x016 2 每FAT表占用扇区数 ,小于32M使用 0x0000 
0x018 2 逻辑每磁道扇区数  0x003F 
0x01A 2 逻辑磁头数  0x00FF
0x01C 4 系统隐含扇区数  0x00000080
0x020 4 扇区总数,大于32M使用  0x00784F80
0x024 4 每FAT表扇区数,大于32M使用  0x00001E04 
0x028 2 标记  0x0000
0x02A 2 版本 (通常为零) 0x0000
0x02C 4 根目录起始簇  0x00000002 
0x030 2 Boot占用扇区数  0x0001 
0x032 2 备份引导扇区位置  0x0006
0x034 14 保留 14个字节的0x00 
0x042 1 扩展引导标记  0x29 
0x043 4 序列号  0x6A9C4125 
0x047 10 卷标 转成字符即“NO NAME”
0x052 8 文件系统  转成字符即“FAT32” 

我来解释一下其中的几个参数。首先是保留扇区数,它可以理解为是FAT表的起始位置。我们可以先来看一下下面这张图,有助于更好的理解保留扇区数的意思。

可以看到引导扇区后面紧跟这若干保留扇区,至于保留扇区的作用会在下一篇中分析,这里先跳过。而保留扇区的后面紧跟着的是FAT1和FAT2。所以FAT1表的起始地址是(引导扇区+保留扇区)*扇区字节数?不对。这里有个需要注意的地方是,保留扇区数这个参数其实已经包含了引导扇区了,所以在计算FAT1表位置的时候直接通过保留扇区数这个参数来计算偏移就行了。这一点需要特别注意。(这里笔者看了几篇文献的说法不一,有说需要加上保留扇区的,有说不用加的,可能是版本不一样的关系。但是笔者亲自实践之后发现是不需要加上的。)

至于FAT表留到下一篇再讲,这里说明一下为什么FAT会有两张。文件分配表区共保存了两个相同的文件分配表,因为文件所占用的存储空间(簇链)及空闲空间的管理都是通过FAT实现的,FAT如此重要,保存两个以便第一个损坏时,还有第二个可用[4]。这样FAT表个数这个参数也解释了。

  • 程序实现

为了用窗体程序直观的显示各个参数,接下来把上面的程序改写为c#。众所周知,c#调用系统函数大多都需要靠间接调用c的动态库来实现,这里的CreateFile和ReadFile也不例外。下面我们先编写一个FileReader类来提供这些系统api调用。部分代码如下,完整的FileReader点我下载

class FileReader
{
  [System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
static extern unsafe System.IntPtr CreateFile
(
string FileName, // file name
uint DesiredAccess, // access mode
uint ShareMode, // share mode
uint SecurityAttributes, // Security Attributes
uint CreationDisposition, // how to create
uint FlagsAndAttributes, // file attributes
int hTemplateFile // handle to template file
);
  public bool Open(string FileName)
{
// open the existing file for reading
handle = CreateFile
(
FileName,
GENERIC_READ,
FILE_SHARE_WRITE,
,
OPEN_EXISTING,
, ); if (handle != System.IntPtr.Zero)
{
return true;
}
else
{
return false;
}

由于本文的重点不是学习c#窗体编程,所以略过这部分,直接通过调用FileReader提供的系统API并编写窗体程序,效果如下图所示(本程序参考[3]),需要完整工程的读者可以点我下载,请我VS2012及以上打开。

好了,今天这篇文章就先写到这边。由于笔者才疏学浅,对于FAT32也是刚开始学习,如果有错误的地方欢迎批评指正。同时这也是我第一次发随笔,如果排版等方面有不妥的地方也欢迎提出。接下来会继续学习接下去的FAT表区和数据区并继续更新接下来的学习心得。

参考文献:

1、http://baike.baidu.com/view/45233.htm?fr=aladdin

2、FAT32文件格式 http://blog.csdn.net/shrekmu/article/details/5950414

3、读写U盘(FAT32)引导扇区 http://blog.csdn.net/zhanglei8893/article/details/5912903

4、F​A​T​3​2​文​件​系​统​格​式​详​解 http://wenku.baidu.com/link?url=zrGv8nld-bc-7KT_TKbo2vWplaiIHhmJ9_ydRZBZdZ4zy8odQFwS6komz2gz1AHX36T_EN1CKZ_16d19upW9pDauno6zEmpw10wlTSTwcoi

5、基​于​U​盘​F​A​T​3​2​文​件​系​统​的​分​析 http://wenku.baidu.com/link?url=cIKgrwV66y4CoyuOEB1-OhjRY9tnXtIAoZuYEwDCjxbyRomSIiJgBAXGxq6LudfwuopUpYhiVd8TjxrBFoVyPs0NX3OqbnoWjyn4ZAx60Wi

FAT32文件系统学习(1) —— BPB的理解的更多相关文章

  1. FAT32文件系统学习(3) —— 数据区(DATA区)

    FAT32文件系统学习(3) —— 数据区(DATA区) 今天继续学习FAT32文件系统的数据区部分(Data区).其实这一篇应该是最有意思的,我们可以通过在U盘内放入一些文件,然后在程序中读取出来: ...

  2. FAT32文件系统学习(2) —— FAT表

    1.题外话 在继续本文学习FAT32文件系统之前,先来插入一点别的话题.我们都知道U盘有一个属性是容量,就拿笔者的U盘为例,笔者手上的U盘是金士顿的DataTraveler G3 4GB的一个U盘.电 ...

  3. FAT32文件系统学习(上)

    2011-06-02 22:30:48 目的:需要编写SD读图片的底层驱动程序.所以要了解一个SD卡常用文件系统基本概念.累计学习用时2.5小时. 一,FAT32的保留区 1,引导扇区 :引导扇区是F ...

  4. 入门级:理解FAT32文件系统(转载翻译)

    FAT(File Allocation Table ) 这个网页的目的是帮助你理解怎么样在微软FAT32文件系统下取得数据,处理的硬盘的大小通常在500M到几百G之间.FAT是一个相对简单和纯净的文件 ...

  5. SD卡FAT32文件系统格式

    一.声明 1.本文来源和主旨 2.本文测试环境 二.SD卡FAT文件系统 1.SD卡FAT32文件系统的整体布局 2.FAT文件系统简介 ① 文件分配表 ② 目录项 三.DBR(DOS BOOT RE ...

  6. FAT文件系统学习和思考

    FAT(File Allocation Table)文件系统 前两天面试,导师说我基础差,要赶紧补起来了.今天晚上看了FAT32文件系统,基本的信息都是百度百科中"FAT文件系统" ...

  7. 【转载】FAT32文件系统详解

    硬盘是用来存储数据的,为了使用和管理方便,这些数据以文件的形式存储在硬盘上.任何操作系统都有自己的文件管理系统,不同的文件系统又有各自不同的逻辑组织方式.例如:常见的文件系统有FAT,NTFS,EXT ...

  8. FAT和FAT32文件系统的原理

    [转自] http://www.sjhf.net/Article/sjhfdoc/200404/1.html 一.硬盘的物理结构:     硬盘存储数据是根据电.磁转换原理实现的.硬盘由一个或几个表面 ...

  9. FAT32文件系统--For TF卡

    1. TF卡空间是如何分配的? 下面以4GB TF卡为例,通过WinHex工具进行分析,其空间分配如下图所示: FAT32把目录当做文件来管理,所以没有独立的目录区,所有的文件目录项都是在数据区里面的 ...

随机推荐

  1. 让你的app体验更丝滑的11种方法!冲击手机应用榜单Top3指日可待

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由WeTest质量开放平台团队发表于云+社区专栏 一款app除了要有令人惊叹的功能和令人发指交互之外,在性能上也应该追求丝滑的要求,这样 ...

  2. InteliiJ IDEA的安装配置与简单使用

    小Alan前段时间一直在家里搬砖,已经很久没有接触技术了,从今天开始重拾技术,工欲善其事,必先利其器,以前在做Java开发的时候最常用的IDE就是Eclipse莫属了,不过随着岁月的流逝,在2016年 ...

  3. EntityFramework 贪婪加载与延迟加载以及资源回收

    EntityFramework的资源回收 1) Using 内包含Entity的上下文关系,对俩表做Add操作,最好可以直接写一个 entity.SaveChanges(); 完成两张表的同时add操 ...

  4. Oracle EBS CST 成本请求报错

    (文档 ID 430533.1) When running CMCPAW, Periodic Actual Cost Worker,  an error is received in the logf ...

  5. Oracle EBS OPM release step

    --release_step生产批 --created by jenrry SET serveroutput on DECLARE x_return_status VARCHAR2 (1); l_ex ...

  6. 最近用到的 sql 统计操作

    统计操作 1.分组统计group by select id,name,count(*) as '总数'  from test1 group by id,name     --group by   分组 ...

  7. MyEclipse总是quick update解决办法

    这个问题的解决办法是关闭自动更新 1. Windows > Preferences > MyEclipse> Community Essentials, 把选项 "Sear ...

  8. MD5密码加密

    using System; using System.Security.Cryptography; using System.Text; namespace DimoNetwork.Common.DE ...

  9. JDK5 新特性之 可变参数的方法(2)---asList

    > Arrays.asList(T - a)方法的使用 >UnsupportedOperationException分析     Arrays.asList(T - a)方法的使用 pac ...

  10. 使用ramdisk内存分区给常用软件加速

    ::参考内存盘软件https://download.csdn.net/download/zly6tz/9717137cls @echo off ::内存虚拟盘符-内存盘大小自己查看源目录大小 ::下面 ...