FAT32文件操作系統(主要針對SD卡)

    最近的項目用到了SD卡數據讀取,瞭解FAT32系統着實噁心了我一下,分享一下自己的筆記。

   u 盤,sd 卡等小容量存儲介質不存在仔細的 分區。但是 在文件系統初始化的開始我們必須通過 MBR 獲取分區表項的數據,以獲得 CHS、LBA 參數以及分區大小扇區 數,從而得到文件系統的起始物理扇區號。 Microsoft 將使用 DOC 分區體系的磁盤稱爲“主引導記錄(Master Boot recorder, MBR)”磁盤,這 是對於使用“全局 ID 分區表(GUID Partition Table, GPT)磁盤”而言的。

一、主引導扇區

  使用“DOC 分區”體系時,磁盤的第一個——也就是 0 號扇區被稱爲主引導記錄扇區,也稱爲主引導 記錄 MBR(Master Boot recorder,MBR)。 1. MBR 數據結構 MBR 由 446 個字節的引導代碼、64 字節的主分區(4 個)表及兩個字節的簽名值“55 AA”組成。 可以用 WinHex 打開一個 SD 卡的 MBR 查看(即0號扇區)。(注意數據是用高位到低位的方式存儲的)

字段定義如下表(BPB 後面的 422 個字節對我們的意義不大,表中省略):

字段名稱 長度 含義 偏移量
jumpBoot 3 跳轉指令 0
OEMName 8 標記格式化該分區的操作系統名稱與版本號 3
BytesPerClus 2 每扇區字節數 11
SecPerClus 1 每簇扇區數 13
RsvdSecCnt 2 保留扇區數目 14
NumFATs 1 此卷中FAT數 16
RootEntCnt 2 FAT32爲0 17
TotSec16 2 FAT32爲0 19
Media 1 存儲介質 21
FATSz16 2 FAT32爲0 22
SecPerTrk 2 磁道扇區數 24
NumHeads 2 磁頭數 26
HiddSec 4 FAT區前隱扇區數 28
TotSec32 4 該卷總扇區數 32
FATSz32 4 FAT表扇區數 36
ExtFlags 2 FAT32特有 40
FSVer 2 FAT32特有 42
RootClus 4 根目錄簇號 44
FSInfo 2 文件系統信息 48
BKBootSec 2 通常爲6 50
Reserved 12 擴展用 52
DrvNum 1   64
Reserved1 1   65
BootSig 1   66
VolID 4   67
FilSysType 11   71
FilSysType1 8   82

在0號扇區的數據中,只有前90個字節爲有用數據,從表中對應的數據含義可以得出文件系統的具體參數。

在C語言中可以簡單的定義一個結構體來包含我們想要的參數

struct FAT32_DBR
{
 unsigned char BS_jmpBoot[3]; //跳轉指令 offset: 0
 unsigned char BS_OEMName[8]; // offset: 3
 unsigned char BPB_BytesPerSec[2];//每扇區字節數 offset:11
 unsigned char BPB_SecPerClus[1]; //每簇扇區數 offset:13
 unsigned char BPB_RsvdSecCnt[2]; //保留扇區數目 offset:14
 unsigned char BPB_NumFATs[1]; //此卷中 FAT 表數 offset:16
 unsigned char BPB_RootEntCnt[2]; //FAT32 爲 0 offset:17
 unsigned char BPB_TotSec16[2]; //FAT32 爲 0 offset:19
 unsigned char BPB_Media[1]; //存儲介質 offset:21
 unsigned char BPB_FATSz16[2]; //FAT32 爲 0 offset:22
 unsigned char BPB_SecPerTrk[2]; //磁道扇區數 offset:24
 unsigned char BPB_NumHeads[2]; //磁頭數 offset:26
 unsigned char BPB_HiddSec[4]; //FAT 區前隱扇區數 offset:28 
 unsigned char BPB_TotSec32[4]; //該卷總扇區數 offset:32
 unsigned char BPB_FATSz32[4]; //一個 FAT 表扇區數 offset:36
 unsigned char BPB_ExtFlags[2]; //FAT32 特有 offset:40
 unsigned char BPB_FSVer[2]; //FAT32 特有 offset:42
 unsigned char BPB_RootClus[4]; //根目錄簇號 offset:44
 unsigned char FSInfo[2]; //保留扇區 FSINFO 扇區數 offset:48
 unsigned char BPB_BkBootSec[2]; //通常爲 6 offset:50
 unsigned char BPB_Reserved[12]; //擴展用 offset:52
 unsigned char BS_DrvNum[1]; // offset:64
 unsigned char BS_Reserved1[1]; // offset:65
 unsigned char BS_BootSig[1]; // offset:66
 unsigned char BS_VolID[4]; // offset:67
 unsigned char BS_FilSysType[11]; // offset:71
 unsigned char BS_FilSysType1[8]; //"FAT32 " offset:82
};

 

    注意:讀回來的字節拼在一起,與實際的數據並不吻合。例如 BPB_BytesPerSec 讀出來的內容是“00 02”,在程序中我們把 00 作爲 int 型變 量的高字節,把 02 作爲其低字節,那麼這個變量的值爲 2,而實際的 SD 卡里的 扇區大小爲 512 個字節,這 512 與 2 之間相去甚遠。

   是什麼造成這種現象的呢? 這就是大端模式與小端模式在作怪。上面我們合成 int 型變量的方法(00 爲 高字節,02 爲低字節)爲小端模式。而如果我們改用大端模式來進行合成的話, 結果就會不同:將 02 作高字節,而把 00 作低字節,變量值就成了 0x0200(十進 制的 512),這樣就和實際數據吻合了。可見 FAT32 中字節的排布是採用小端模式 的。在我們程序中需要將它轉爲大端模式的表達方式。

二、什麼是文件系統?

  文件系統是爲了長久的存儲和訪問數據而爲用戶提供的一種基於文件和目錄的存儲機制。

  使用硬盤存儲數據之前,首先要進行分區(當然你也可以不分區),然後對分區(或整個硬盤)進行格式 化,其實格式化的過程就是在分區內建立文件系統的過程。一個文件系統由系統結構和按一定規則存放的 用戶數據組成。比如,如果在 windows 下當我們要格式化一個分區或是其他存儲介質時, windows 會彈出一個對話框,上面有這樣一些選擇內容:容量、文件系統、分配單元大小、卷標等等。其中文件系統的下拉菜單中就有幾種不同的文件系統共供戶選擇,一般我們都會選擇默認、FAT32 或 NTFS 文 件系統,當我們按下格式化按鈕後,操作系統就開始爲這個分區建立你所選擇的文件系統。

   文件系統種類繁多,但所有的文件系統都有一定的共性 :

    1. 數據單元 數據在寫入磁盤或從磁盤讀取數據時每次操作的數據量稱爲數據單元,它的大小在建立文件系統時確 定。數據單元在不同的文件系統中有不同的稱呼:例如在 FAT 和 NTFS 文件系統中稱作“簇(Cluster)”, ExtX 中稱作“塊(Block)”等。一個數據單元由若干個連續的扇區組成,大小總是 2 的整數次冪個扇區。

    2. 壞數據單元 壞數據單元也就是包含缺陷扇區的數據單元。

    3. 邏輯文件系統地址 磁盤上的一個扇區在不同的情況下會有不同的地址表達形式。 &每個扇區都會有一個 LBA 地址,也就是物理地址 &每個物理卷內的扇區又有一個物理卷地址 &在邏輯卷內部的扇區會有一個邏輯卷地址 (以上幾個概念比較容易混淆,注意區分)

    4. 邏輯文件地址 對於每個文件來說,將它按所在文件系統中的數據單元大小爲單位進行分割,分割後的每一個部分由 0 開始編號,這個編號就是其對應數據單元的邏輯文件地址。一個文件前後相鄰的兩個數據單元在物理上 的存儲地址可能是不連續的,但它的邏輯文件地址一定是連續的。

    5. 分配策略 【1】第一可用分配策略,即當爲一個文件分配了一個存儲單元后還要繼續爲其分配時,操作系統會重新從文件系統的起始處搜索可以使用的空間。

【2】下一可用分配策略,即爲文件分配了一個儲存單元后並不再回到捲開始處重新尋找可用空間,而是直接向後進行搜索。

【3】最佳分配策略,即在爲文件分配空間時,會盡可能找到足夠的連續空間以避免其片段化。

   6. 鬆弛空間 鬆弛空間分爲兩種,一種是數據的結尾與爲其分配的空間結束處的未使用部分,還有一種就是位於分 區結尾的卷鬆弛空間。

   7.元數據 任何文件和目錄都會有一個名字,我們將其統稱爲“文件名”。除了文件名外,文件或目錄還有其他 一些描述信息,如大小,時間信息,是否加密或壓縮,儲存位置信息等,我們將這些描述信息統稱爲文件 或目錄的元數據。(這部分數據也是我們讀取寫入的關鍵)

 三、對FAT32的簡單介紹

    FAT(File Allocation Table,文件分配表)文件系統是 windows 操作系統所使用的一種文件系統, 它的發展過程經歷了 FAT12、FAT16、FAT32 三個階段。

   FAT 文件系統用“簇”作爲數據單元。一個“簇”由一組連續的扇區組成,簇所含的扇區數必須是 2 的整數次冪。簇的最大值爲 64 個扇區,即 32KB。所有簇從 2 開始進行編號,每個簇都有一個自己的地址 編號。用戶文件和目錄都存儲在簇中。

   FAT 文件系統的數據結構中有兩個重要的結構:文件分配表和目錄項: &文件和文件夾內容儲存在簇中,如果一個文件或文件夾需要多餘一個簇的空間,則用 FAT 表來描述 如何找到另外的簇。FAT 結構用於指出文件的下一個簇,同時也說明了簇的分配狀態。FAT12、FAT16、FAT32 這三種文件系統之間的主要區別在與 FAT 項的大小不同。 &FAT 文件系統的每一個文件和文件夾都被分配到一個目錄項,目錄項中記錄着文件名、大小、文件內 容起始地址以及其他一些元數據。

   在 FAT 文件系統中,文件系統的數據記錄在“引導扇區中(DBR 和MBR其實是一個東西)”中。引導扇區位於整個文件系統的 0 號扇區,是文件系統隱藏區域(也稱爲保留區)的一部分,我們稱其爲 DBR(DOS Boot Recorder——DOS 引導記錄)扇區,DBR 中記錄着文件系統的起始位置、大小、FAT 表個數及大小等相關信息。 在 FAT 文件系統中,同時使用“扇區地址”和“簇地址”兩種地址管理方式。這是因爲只有存儲用戶 數據的數據區使用簇進行管理(FAT12 和 FAT16 的根目錄除外),所有簇都位於數據區。其他文件系統管理 數據區域是不以簇進行管理的,這部分區域使用扇區地址進行管理。文件系統的起始扇區爲 0 號扇區。

說明: 【1】 保留區含有一個重要的數據結構——系統引導扇區(DBR)。FAT12、FAT16 的保留區通常只有 一個扇區,而 FAT32 的保留扇區要多一些,除 0 號扇區外,還有其他一些扇區,其中包括了 DBR 的備份扇區。

【2】 FAT 區由來年各個大小相等的 FAT 表組成——FAT1、FAT2,FAT2 緊跟在 FAT1 之後。

【3】 FAT12、FAT16 的根目錄雖然也屬於數據區,但是他們並不由簇進行管理。也就是說 FAT12、 FAT16 的根目錄是沒有簇號的,他們的 2 號簇從根目錄之後開始。而 FAT32 的根目錄通常位 於 2 號簇。

1.保留區

FAT32 文件系統的開始部分有一個由若干個扇區組成的保留區,保留區的大小會記錄在 DBR 扇區中, 比較常見的大小爲 32、34 或 38 個扇區。

(1).引導扇區

關於DBR或者MBR中關於磁盤的具體信息可以在第一部分中看到。

(2).引導代碼

  FAT 文件系統將引導代碼與文件形同數據結構融合在一起,而不像 Unix 文件系統那樣各自存在,引導 扇區的前三個字節爲一個由機器代碼構成的跳轉指令,以使 CPU 越過跟在後面的配置數據跳轉到配置數據 後面的引導代碼處。

  FAT32 文件系統引導扇區的 512 字節中,90~509 字節爲引導代碼(即在0扇區除了引導扇區的剩餘部分),而 FAT12/16 則是 62~509 字節爲引 導代碼。同時,FAT32 還可以利用引導扇區後的山區空間存放附加的引導代碼。 一個 FAT 卷即使不是可引導文件文件系統,也會存在引導代碼。

(3)。FSINFO 信息扇區

 FAT32 在保留區中增加了一個 FSINFO 扇區,用以記錄文件系統中空閒簇的數量以及下一可用簇的簇號 等信息,以供操作系統作爲參考。 1. FSINFO 信息扇區結構 大多數的 FSINFO 信息扇區一般位於文件系統的 1 號扇區,結構非常簡單。

【1】0x00~0x03: 4 個字節,擴展引導標誌“52526141”。

【2】0x04~0x1E3:480 個字節,未使用,全部置 0。

【3】0x1E4~0x1E7: 4 個字節,FSINFO 簽名“72724161”。

【4】0x1E8~0x1EB: 4 個字節,文件系統的空簇數,4294967295(0xFF FF FF FF)。

【5】0x1EC~0x1EF: 4 個字節,下一可用簇號,2(0x 00 00 00 02)。

【6】0x1F0~0x1FD: 14 個字節,未使用。

【7】0x1FE~0x1FF: 2 個字節,“55 AA”標誌。

通常情況下,文件系統的 2 號扇區結尾也會被設置“55 AA”標誌。6 號扇區也會有一個引 導扇區的備份,相應的,7 號扇區應該是一個備份 FSINFO 信息扇區。8 號扇區可以看做是 2 號扇區的備份, 它的結尾也會有一個“55 AA”標誌。

2.FAT表

     (1). FAT 表概述 :位於保留區後的是 FAT 區,有兩個完全相同的 FAT(File Allocation Table, 文件分配表)表組成, FAT 文件系統的名字也是因此而來。

     重要說明: 1. 對於文件系統來說,FAT 表有兩個重要作用:描述簇的分配狀態以及標明文件或目錄的下一簇的 簇號。

     2. 通常情況下,一個 FAT 把文件系統會有兩個 FAT 表,但有時也允許只有一個 FAT 表,FAT表的具體個數記錄在引導扇區的偏移 0x10 字節處。

     3. 由於 FAT 區緊跟在文件系統保留區後,所以 FAT1 在文件系統中的位置可以通過引導記錄中偏移 0x0E~0x0F 字節處的“保留扇區數”得到。

     4. FAT2 緊跟在FAT1 之後,它的位置可以通過 FAT1 的位置加上 FAT 表的大小扇區數計算出來。

    (2). FAT 表的特性 :

       FAT 表由一系列大小相等的 FAT 表項組成,總的說來 FAT 表有如下特性:

      1. FAT32 中每個簇的簇地址,是有 32bit(4 個字節)記錄在 FAT 表中。FAT 表中的所有字節位置以 4 字節爲單位進行劃分,並對所有劃分後的位置由 0 進行地址編號。0 號地址與 1 號地址被系統 保留並存儲特殊標誌內容。從 2 號地址開始,每個地址對應於數據區的簇號,FAT 表中的地址編 號與數據區中的簇號相同。我們稱 FAT 表中的這些地址爲 FAT 表項,FAT 表項中記錄的值稱爲 FAT 表項值。

       2. 當文件系統被創建,也就是進行格式化操作時,分配給 FAT 區域的空間將會被清空,在 FAT1 與 FAT2 的 0 號表項與 1 號表項寫入特定值。由於創建文件系統的同時也會創建根目錄,也就是爲根 目錄分配了一個簇空間,通常爲 2 號簇,所以 2 號簇所對應的 2 號 FAT 表項也會被寫入一個結束 標記。

       3. 如果某個簇未被分配使用,它所對應的 FAT 表項內的 FAT 表項值即用 0 進行填充,表示該 FAT 表 項所對應的簇未被分配。

       4. 當某個簇已被分配使用時,則它對應的 FAT 表項內的 FAT 表項值也就是該文件的下一個存儲位置 的簇號。如果該文件結束於該簇,則在它的 FAT 表項中記錄的是一個文件結束標記,對於 FAT32 而言,代表文件結束的 FAT 表項值爲 0x0FFFFFFF。         5. 如果某個簇存在壞扇區,則整個簇會用 FAT 表項值 0xFFFFFF7 標記爲壞簇,不再使用,這個壞簇 標記就記錄在它所對應的 FAT 表項中。

       6. 由於簇號起始於 2 號,所以 FAT 表項的 0 號表項與 1 號表項不與任何簇對應。FAT32 的 0 號表項 值總是“F8FFFF0F”。如上圖所示。

        7. 1 號表項可能被用於記錄髒標誌,以說明文件系統沒有被正常卸載或者磁盤表面存在錯誤。不過 這個值並不重要。正常情況下 1 號表項的值爲“FFFFFFFF”或“FFFFFF0F”。

        8. 在文件系統中新建文件時,如果新建的文件只佔用一個簇,爲其分配的簇對應的 FAT 表項將會寫 入結束標記。如果新建的文件不只佔用一個簇,則在其所佔用的每個簇對應的 FAT 表項中寫入爲 其分配的下一簇的簇號,在最後一個簇對應的 FAT 表象中寫入結束標記。

        9. 新建目錄時,只爲其分配一個簇的空間,對應的 FAT 表項中寫入結束標記。當目錄增大超出一個 簇的大小時,將會在空閒空間中繼續爲其分配一個簇,並在 FAT 表中爲其建立 FAT 錶鏈以描述它 所佔用的簇情況。

        10. 對文件或目錄進行操作時,他們所對應的 FAT 表項將會被清空,設置爲 0 以表示其所對應的簇處 於未分配狀態。

3.數據區

   (1) 根目錄

     雖然原則上 FAT32 允許根目錄位於數據去的任何位置,但通常情況下它都位於 2 號簇。 1. 定位根目錄 在 FAT 文件系統中,尋找第一簇(即 2 號簇)的位置也就是尋找數據區的開始位置,這並不是一件容 易的事,因爲它不是位於文件系統開始處,而是位於數據區。在數據區前面是保留區域和 FAT 區域,這兩 個區域都不使用 FAT 表進行管理。因此,數據區以前的區域只能使用扇區地址(邏輯卷地址),而無法使用 簇地址。 要想定位一個 FAT32 文件系統的數據起始處,可以通過引導扇區的相關參數計算出來。

     1.從引導扇區 的偏移 0x0E~0x0F 字節處得到保留扇區。

     2.從偏移 0x10 字節處得到 FAT 表的個數。

     3.從偏移 0x24~0x27 字 節處得到每個 FAT 表的大小扇區數。

     4.利用如下公式計算: 保留扇區數 + 每個 FAT 表大小扇區數 × FAT 表個數 = 數據區起始扇區號

     要想計算其他已知簇號的扇區號,還要由引導扇區的偏移 0x0D 字節處查找到每個簇大小扇區數,並 使用如下公式計算: 某簇起始扇區號 = 保留扇區數 + 每個 FAT 表大小扇區數 × FAT 表個數 + (該簇簇號 - 2) × 每簇扇 區數。

(2)文件或子目錄

【1】0x00~0x00:1 個字節,如果該目錄項正在使用中,則爲文件名或子目錄名的第一個字符。  0x00:說明該目錄項未被分配使用。  0xE5:說明該目錄項曾經被使用過,但是現在已被刪除。目前處於未分配狀態

【2】0x01~0x0A:10 個字節,文件名的第 2 至第 11 個 ASCII 碼,除擴展名外,如果文件的名字不足 8 個字符則用 0x20 進行填充。

【3】0x0B~0x0B:1 個字節,所描述文件的屬性  0x01-只讀  0x02-隱藏  0x04-系統文件  0x08-卷標  0x0F-爲此值時表示該目錄項爲長文件名目錄項  0x10-目錄  0x20-存檔

【4】0x0C~0x0C:1 字節,保留

【5】0x0D~0x0D:1 個字節,文件穿件的時間,精確到創建時刻的十分之一秒

【6】0x0E~0x0F:2 個字節,文件創建的時間——時分秒 兩個字節的 16bit 被劃分爲 3 個部分:  0~4bit 爲秒,以 2 秒爲單位,有效值爲 0~29,可以表示的時刻爲 0~58  5~10bit 爲分,有效值爲 0~59  11~15bit 爲時,有效值爲 0~23 下面舉例說明: 如上圖所示,其子目錄項偏移 0x0E~0x0F 字節處的內容爲“A1A9”,我們來計算一下。由於 FAT 文件系 統數據採用的小端存儲方式,因此“A1A9”表示成 16進製爲 0xA9A1,換算成 2進制就是 1010 1001 1010 0001, 我們將其分成三部分並計算它的值,如下圖所示: 下面我們再回過頭來看看丫頭這個目錄的屬性,點擊右鍵選擇屬性一項可以看到: 可以看到上面的創建時間是 21:13:03,在誤差允許的範圍內。

【7】0x10~0x11:2 個字節,文件創立的日期,16bit 也劃分爲三個部分:  0~4bit 爲日,有效值爲 1~31  5~10bit 爲月,有效值爲 1~12  11~15bit 爲時,有效值爲 0~127,這是一個相對於 1980 年的年數值,也就是說該值加上 1980 即爲文件創建的日期值。該部分筆者就不再舉例就計算了,原理和計算創建時間是一樣的。請 讀者自己去計算。

【8】0x12~0x13:2 個字節,最後訪問日期。

【9】0x14~0x15:2 個字節,文件起始簇號的高兩個字節。

【10】0x16~0x17:2 個字節,文件最後修改的時間。

【11】0x18~0x19:2 個字節,文件最後被修改時的日期。

【12】0x1A~0x1B:文件內容起始簇號的低兩個字節,與 0x14~0x15 字節處的高兩個字節組成文件內容 起始簇號。

【13】0x1C~0x1F:文件內容大小字節數,只對文件有效,子目錄的目錄項此處全部設置爲 0。

 

四、總結

    這時候我們想要讀取SD卡(FAT32系統)中具體某一文件的數據的步驟就很清晰了。

  (1).首先從0扇區中讀取出磁盤的基本信息,得到根目錄的位置。

  (2).將根目錄所在扇區的位置讀取出來,找到目標文件的起始簇號。

  (3).找到文件對應的FAT表項對文件進行順序讀取。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章