新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 牛人業(yè)話 > SD卡FAT16文件系統(tǒng)的學(xué)習(xí)筆記

SD卡FAT16文件系統(tǒng)的學(xué)習(xí)筆記

作者: 時(shí)間:2016-07-18 來源:網(wǎng)絡(luò) 收藏

  一、 讀文件的流程

本文引用地址:http://butianyuan.cn/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

  先讀取的第一個(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,代表該友248223個(gè)扇區(qū),因?yàn)槊總€(gè)扇區(qū)有512字節(jié),所以該容量為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代表的就是“ ”的ASCII碼,說明這SD卡是的格式

  四、 文件系統(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表的簡(jiǎn)單介紹

  讀取文件之前要先詳細(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)容。



關(guān)鍵詞: FAT16 SD卡

評(píng)論


相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉