SD卡FAT16文件系統(tǒng)的學(xué)習(xí)筆記
一、 讀文件的流程
本文引用地址:http://2s4d.com/article/201607/294155.htm讀物理扇區(qū)0,得到引導(dǎo)扇(邏輯扇區(qū)0)的偏移地址。
讀引導(dǎo)扇的內(nèi)容,得到文件系統(tǒng)基本配置信息。
根據(jù)文件系統(tǒng)的基本配置信息計(jì)算FAT,F(xiàn)DT,數(shù)據(jù)簇的起始地址和大小。
根據(jù)要讀的文件名搜索FDT表,找到要讀文件的起始數(shù)據(jù)簇編號(hào),大小。
根據(jù)文件的起始數(shù)據(jù)簇編號(hào)在FAT表中查找所有該文件占用的數(shù)據(jù)簇及數(shù)據(jù)簇訪問的先后關(guān)系。
讀取該文件的起始數(shù)據(jù)簇的內(nèi)容,及下一數(shù)據(jù)簇內(nèi)容(有需要時(shí))。
二、 讀取物理扇區(qū)0
先讀取SD卡的第一個(gè)扇區(qū)(512字節(jié)),即扇區(qū)0,然后該扇區(qū)最后部分的數(shù)據(jù)如下圖所示
正常的話,該扇區(qū)最后兩個(gè)字節(jié)如上圖所示為55 AA,如果不是則證明是讀錯(cuò)了,或者該SD沒有被格式化。
該扇區(qū)有兩個(gè)重要信息:
一、 在0x1ca開始的四個(gè)字節(jié)9f c9 03 00,即0x3c99f=248223,代表該SD卡友248223個(gè)扇區(qū),因?yàn)槊總€(gè)扇區(qū)有512字節(jié),所以該SD卡容量為248223*512/1024/1024=121.2MByte
二、在0x1c6開始的四個(gè)字節(jié)61 00 00 00,即0x61=97,它表示引導(dǎo)扇區(qū)在扇區(qū)97。那我們就接著讀扇區(qū)97,獲取SD卡里更詳細(xì)的信息,這個(gè)扇區(qū)0就可以不用管了。
三、 讀取引導(dǎo)扇區(qū)
以下是扇區(qū)97前64Byte的內(nèi)容。因?yàn)?7*512=0xc200,所以可以下圖左邊的偏移地址為c200
首先第0x3到0xA的內(nèi)容為ASCII碼的“MSDOS5.0”,不是重要信息
第0xb開始的兩個(gè)字節(jié)00 02,即0x2000=512,代表每個(gè)扇區(qū)(sector)有512個(gè)字節(jié)(byte)
接下來的04代表每個(gè)簇(cluster)有4個(gè)扇區(qū)
接下來的04 00 即0x4代表有4-1個(gè)保留扇區(qū),即是第一個(gè)FAT表所在扇區(qū)為引導(dǎo)扇區(qū)(97)+4=扇區(qū)101
接下來的02 代表有兩個(gè)FAT表
接下來的00 02,即0x2000=512,代表FDT(目錄區(qū))有512登記項(xiàng)
第0x16開始的兩個(gè)字節(jié)f2 00,即0xf2=242,代表每個(gè)FAT表占242個(gè)扇區(qū)
第0x36到0x3d代表的就是“FAT16 ”的ASCII碼,說明這SD卡是FAT16的格式
四、 FAT16文件系統(tǒng)的結(jié)構(gòu)
知道以上的信息之后我們就可以根據(jù)以上信息計(jì)算出FAT1,F(xiàn)AT2,F(xiàn)DT和數(shù)據(jù)簇的首地址和結(jié)束地址,但在計(jì)算之前,我有必要介紹一下整個(gè)FAT16文件系統(tǒng)的結(jié)構(gòu)和各個(gè)區(qū)的含義與作用。
五、 獲取文件系統(tǒng)基本配置信息
現(xiàn)在既然已經(jīng)大概了解了引導(dǎo)扇,F(xiàn)AT1,F(xiàn)AT2,F(xiàn)DT和數(shù)據(jù)簇的作用,接下來就說一下怎么計(jì)算它們的起始地址和結(jié)束地址。我們用扇區(qū)來作為地址單位。
我們首先定義兩個(gè)結(jié)構(gòu)體
typedef struct
{
U16 BytesPerSector; //每個(gè)扇區(qū)多少字節(jié)
U8 SectorsPerCluster; //每個(gè)簇有多少個(gè)扇區(qū)
U16 ReserveSectors; //保留扇區(qū)數(shù)
U8 FatTableNums; //有多少個(gè)FAT表
U16 RootDirRegNums; //根目錄允許的登記項(xiàng)數(shù)目
U16 SectorsPerFat; //每個(gè)FAT表有多少個(gè)扇區(qū)
U32 SectorNums; //總的扇區(qū)數(shù)
U8 FileType[7]; //文件系統(tǒng)類型
}FAT_PARA;
typedef struct
{
U32 Logic; //引導(dǎo)扇(邏輯扇區(qū)0)對(duì)物理0扇區(qū)里的偏移地址
U32 FAT1;
U32 FAT2;
U32 FDT;
U32 Cluster; //數(shù)據(jù)簇的偏移地址
}FAT_OFFSET;
FAT_PARA SD_para; //聲明兩個(gè)結(jié)構(gòu)體變量
FAT_OFFSET SD_offset;
由之前的知識(shí)可以知道,我們首先從物理扇區(qū)0知道SD_offset.Logic的地址,然后就可以找到引導(dǎo)扇.然后再在引導(dǎo)扇里找到SD_para里面所有變量的值。
U8 buffer[512];
Read_Single_Block(0, buffer);//把物理扇區(qū)0的512個(gè)字節(jié)的數(shù)據(jù)讀到buffer里
SD_offset.Logic = (* (U16 *) (buffer + 0x1c6)) + ((* (U16 *) (buffer + 0x1c8)) << 16); //得到引導(dǎo)扇的偏移地址
Read_Single_Block(SD_offset.Logic, buffer) ; //讀引導(dǎo)扇的數(shù)據(jù)
//獲取參數(shù),以便計(jì)算各個(gè)區(qū)的偏移地址
SD_para.BytesPerSector = (* (U8 *) (buffer + 0xb)) + ((* (U8 *) (buffer + 0xc)) << 8);
SD_para.SectorsPerCluster = * (buffer + 0x0d);
SD_para.ReserveSectors = * (U16 *) (buffer + 0x0e);
SD_para.FatTableNums = * (buffer + 0x10);
SD_para.RootDirRegNums = (* (U8 *) (buffer + 0x11)) + ((* (U8 *) (buffer + 0x12)) << 8);
SD_para.SectorsPerFat = * (U16 *) (buffer + 0x16);
SD_para.SectorNums = * (U32 *) (buffer + 0x20);
for(i = 0; i < 6; i++)
SD_para.FileType[i] = *(buffer+0x36+i);
SD_para.FileType[6] = 0;
六、 計(jì)算各重要區(qū)域的大小與起始地址
//計(jì)算各個(gè)區(qū)的偏移地址
//FAT1地址=引導(dǎo)扇地址+保留扇區(qū)數(shù),大小為SD_para.SectorsPerFat
SD_offset.FAT1 = SD_offset.Logic + SD_para.ReserveSectors;
//如果存在兩個(gè)FAT表,一般不是1就是2
if (SD_para.FatTableNums == 2)
//FAT2地址=FAT1地址+ SD_para.SectorsPerFat
SD_offset.FAT2 = SD_offset.FAT1 + SD_para.SectorsPerFat;
else SD_offset.FAT2 = 0;
//FDT地址=FAT1+FAT表數(shù)*FAT表大小
SD_offset.FDT=SD_offset.FAT1+SD_para.FatTableNums*SD_para.SectorsPerFat;
//因?yàn)閿?shù)據(jù)簇2緊跟在FDT后,所以數(shù)據(jù)簇0易求得
SD_offset.Cluster = SD_offset.FDT + 32 - 2 * SD_para.SectorsPerCluster;
七、 FDT與FAT表的簡單介紹
讀取文件之前要先詳細(xì)了解一下FDT,和FAT表的內(nèi)容
一個(gè)FDT表占32個(gè)扇區(qū),共有512個(gè)文件登記信息,所以每個(gè)文件登記信息的大小為32*512/512=32Byte
每個(gè)文件登記信息如下圖所示
對(duì)于我們來說,這個(gè)文件記錄信息最重要的就是最后六個(gè)字節(jié)
最后四個(gè)字節(jié)代表文件大小,由文件大小可以推算出該文件占用多少個(gè)數(shù)據(jù)簇
第0x1a到0x1b個(gè)字節(jié)道標(biāo)文件開始的首簇號(hào),知道文件的首簇號(hào)我們就可以查看FAT表的相應(yīng)信息,就可得到該文件所占用的所有數(shù)據(jù)簇的簇號(hào)。
以下是FAT表的結(jié)構(gòu)
上表中,06、07單元映射了磁盤3號(hào)簇區(qū)。有之前的介紹中可以知道,我這張SD卡1個(gè)簇包含4個(gè)扇區(qū)。也就是說在寫數(shù)據(jù)時(shí),只有寫完了3號(hào)簇的4個(gè)扇后,將FAT表的06,07單元填寫04,00;才可繼續(xù)在04號(hào)簇上寫數(shù)據(jù)。如果數(shù)據(jù)寫完后還沒有寫滿3號(hào)簇,則在FAT表的06,07單元填寫FF,F(xiàn)F.
也就是說在FAT表中記錄著每個(gè)數(shù)據(jù)簇的狀態(tài),且每個(gè)數(shù)據(jù)簇的狀態(tài)占用兩個(gè)字節(jié)。如果這兩個(gè)字節(jié)等于0xffff,則代表該數(shù)據(jù)簇以被占用,且文件在該數(shù)據(jù)簇中結(jié)束。如果這兩個(gè)字節(jié)等于0x0001~0xfffe,則代表該數(shù)據(jù)簇已被占用,且該文件沒有結(jié)束,而該文件存放的下一數(shù)據(jù)簇的簇號(hào)就等于這兩個(gè)字節(jié)的大小。
八、 讀取一個(gè)文件
下面以我的SD卡為例子,向大家介紹讀寫SD的FAT文件系統(tǒng)的文件(最好先安裝一個(gè)叫做winhex的軟件)。
首先我的SD卡存放著這樣一個(gè)文件
要打開我這個(gè)名為lqz.txt的文件的,我們先查找FDT表中關(guān)于lqz.txt這個(gè)文件的登記信息。
因?yàn)橹耙呀?jīng)知道了FDT的首地址是第585扇區(qū),我們來到585扇區(qū),開始搜索LQZ.TXT(必須先轉(zhuǎn)換成大寫字母)
最后在地址為0x4a310(也就是第0x4a310/512=593扇區(qū))的地方搜索到LQZ.TXT的文件登記信息,在最后四個(gè)字節(jié)得知該文件大小為0x00002c89=11401Byte,占用11401/512/4=6個(gè)數(shù)據(jù)簇,從倒數(shù)第5,6個(gè)字節(jié)可以知道文件的首簇號(hào)為0x2fe4,然后在FAT表根據(jù)文件的首簇號(hào)查找接下來文件占用的五個(gè)數(shù)據(jù)簇簇號(hào),數(shù)據(jù)簇0x2fe4在FAT的登記位置=FAT地址+0xfe4*2=0xca00+0x2fe4*2=0x129c8,我們來到0x129c8這個(gè)地址
數(shù)據(jù)簇0x2fe4的信息就存放在0x129c8,和0x129c9這個(gè)字節(jié)里,從上圖可以看出這兩個(gè)字節(jié)等于0x46F4,也就是說LQZ.TXT存放的下一個(gè)數(shù)據(jù)簇的簇號(hào)為0x46F4,由于該文件占用6個(gè)數(shù)據(jù)簇,所以我們必須繼續(xù)查找剩下的4個(gè)數(shù)據(jù)簇的簇號(hào)。我們繼續(xù)查找簇號(hào)為0x46f4的數(shù)據(jù)簇在FAT表的信息,地址為0xca00+0x46f4*2=0x157e8
由上圖可以下一數(shù)據(jù)簇的簇號(hào)為0x46f5。然后按照上訴方法查找剩余三個(gè)簇號(hào)分別為0x46f6,0x46f7,0x46f8,最后在0x46f8對(duì)應(yīng)的地方存放著0xffff,代表文件到此結(jié)束。
經(jīng)過上訴步驟我們知道我lqz.txt文件依次存放在0x2fe4,0x46f4,0x46f5,0x46f6,0x46f7,0x46f8這6個(gè)數(shù)據(jù)簇,接下來我們就讀取這6個(gè)數(shù)據(jù)簇的內(nèi)容即可。
比如說:數(shù)據(jù)簇0x2fe4的地址=數(shù)據(jù)簇0地址+0x2fe4*4*512=0x4c200+0x2fe4*4*512=0x183e200,0x183e200/512=49649,也就是在物理扇區(qū)49649~49652這個(gè)四個(gè)扇區(qū)都是數(shù)據(jù)簇0x2fe4的內(nèi)容。
評(píng)論