複合文檔格式研究之05-DIFAT、FAT、MINIFAT

李懿 Excel學習 2016-07-05

微信掃一掃
關注該公衆號

需要之前的文章,請在公衆號內回覆:

複合文檔

 

5、讀取DIFATFATMINIFAT

上一次,我們成功讀取了文件頭Header。這一次,我們要根據Header中的信息讀取DIFAT,FAT和MINIFAT。這三個信息至關重要,它直接關係到我們數據真正的存儲順序。在那之前,先來複習並擴展一下這些基本的概念。

5.1 文件和扇區

是否還記得第一部分我們介紹的基礎知識呢?數據存儲是以扇區爲單位的,對於文件也是一樣。一個文件可能佔用多個扇區。對於複合文檔,每個不同類型的數據都是單獨存放在不同扇區的,換句話說,一個扇區內只存放一種類型的數據。有些扇區存放FAT信息,有些存放DIFAT信息,有些則存放普通的文件的數據。


22         文件和扇區示例

如上圖所示,除去文件頭外,每個扇區從開始到最後都有一個從0開始的數字編號。若要讀取某個扇區的信息,我們要獲取扇區相對於文件開頭的偏移量,可以採用以下的公式:

扇區ID x 扇區大小 + 512

其中512是文件頭佔用的空間,文件頭之後的0號扇區的偏移量就是0*512+512=512,依此類推。

5.2  扇區ID

前文所述一個扇區只會存放一種類型的數據,因而在複合文檔的FAT數據中,除了表示扇區ID的數字,還有些特殊的數字ID表示一些特定的扇區。


 23         扇區ID類型

爲了方便使用,根據扇區類型,可以聲明一些枚舉值如下:

Public Enum SECTORTYPE
   MAXREGSECT = &HFFFFFFFA
   NASECT = &HFFFFFFFB   
   DIFSECT = &HFFFFFFFC   
   FATSECT = &HFFFFFFFD   
   ENDOFCHAIN = &HFFFFFFFE

   FREESECT = &HFFFFFFFF

End Enum

 

5.3 FAT

FAT中記錄所有扇區的詳細信息,包括扇區的類型,數據扇區的順序等等。

可以把FAT當成一個數組,數組中存儲的都是Long類型的整數(4個字節),則其中的每個整數代表一個扇區的ID,代表了數據區域下一個扇區的ID。我們用一個下標起始爲0(與扇區ID同步)的數組來表示FAT,來看一個具體的示例。


 24         FAT示例

上圖對應了之前的那個文件FAT[0]表示了0號扇區,這個扇區以及4、5號扇區存儲了FAT的信息,因而其中存儲了十六進制數0xFFFFFFFD。3、6號扇區爲DIFAT扇區,因而其中存儲了十六進制數0xFFFFFFFC。扇區1、2、N存放了正常的文件數據,因而其數字表示的是該扇區的下一個數據扇區的ID,比如與1號扇區連續的下一個數據扇區是2號,與2號扇區連續的下一個數據扇區是7號。而在N號扇區的FAT中存放了0xFFFFFFFE,表示這個扇區之後沒有更多數據扇區。

通常一個扇區大小爲512字節,因而一個FAT扇區中,最多可以存放128組FAT信息。在一個扇區內部,這些FAT的信息都是連續的,即FAT所表示的扇區都是連續的。比如某個FAT扇區,第1個FAT代表的扇區的ID是51的話,則這個扇區可以表示ID從51到178的扇區。

要把不同的FAT扇區串聯起來的方法則是通過DIFAT列表。

5.4 DIFAT

DIFAT是FAT扇區的索引,表示了FAT扇區的前後順序。DIFAT和FAT類似,也可以用數組表示,其存儲值表示了FAT扇區的正確讀取順序。

除了Header中存儲的109個DIFAT數據,還可以使用其它扇區專門存儲DIFAT數據。作爲DIFAT扇區,由於其可能有存在多個扇區組合,並且它沒有額外的索引表示其順序,因而其存儲的數據不像FAT扇區那樣全部都用於存儲FAT數據。在DIFAT扇區的最後4個字節,存儲了下個DIFAT扇區的ID,以表示下個DIFAT數據該去哪兒找。


圖25         DIFAT扇區示意

5.5 使用VBA解析DIFAT

前109個DIFAT存儲在Header之中,若DIFAT超過109個,則在Header中可以通過DIFATSectorStart讀取第一個DIFAT扇區的ID,然後讀取該扇區的127個DIFAT信息。最後一個Long類型的數據即爲下一個DIFAT扇區的ID。

我們添加以下代碼:

'讀取DIFAT

Sub ReadDIFAT(FS As Integer, Hdr As CFBHeader, DIFAT() As Long, SectorSize As Long)

   Dim i   As Long

   '先讀取Header中的DIFAT

   For i = 0 To 108

        '遇到結束ID,則跳出

        If Hdr.DIFAT(i) = SECTORTYPE.ENDOFCHAIN Or Hdr.DIFAT(i) = SECTORTYPE.FREESECT Then

            Exit Sub

        End If

        '添加DIFAT

        AddItem2List DIFAT, Hdr.DIFAT(i)

   Next i

   '若還有其他DIFAT扇區,則繼續讀取

   If Hdr.DIFATSectorCount > 0 Then _

        ReadDIFATSector FS, DIFAT,Hdr.DIFATSectorStart, SectorSize

End Sub

 

'讀取指定扇區的DIFAT數據

Sub ReadDIFATSector(FS As Integer,DIFAT() As Long, SectorID As Long, SectorSize As Long)

   Dim i   As Long

   Dim ID  As Long

   '定位

   Seek FS, GetFileOffset(SectorID, SectorSize)

   '讀取DIFAT。在一個DIFAT扇區中,最多有127個DIFAT數據,最後一個爲下一個DIFAT扇區的ID

   For i = 0 To 126

        '讀取數據

        Get FS, , ID

        '遇到結束ID,則跳出

        If ID = SECTORTYPE.ENDOFCHAIN Or ID = SECTORTYPE.FREESECT Then

            Exit Sub

        End If

        '添加DIFAT

        AddItem2List DIFAT, ID

   Next i

   '讀取下一個DIFAT扇區的ID

   Get FS, , ID

   '採用遞歸,調用自己繼續讀取

   ReadDIFATSector FS, DIFAT, ID, SectorSize

End Sub

首先用ReadDIFAT方法,來讀取Header中的前109個DIFAT信息,然後判斷是否存在DIFAT扇區,若存在,則調用方法讀取該扇區。在ReadDIFATSector中,順序讀取前127個DIFAT信息,然後讀取最後一個信息,即爲下一個DIFAT扇區的位置,然後調用方法本身繼續讀取。

注:代碼中使用了一個AddItem2List的方法,把數據添加到數組中。

5.6 使用VBA解析FAT

解析FAT的程序與解析類似,唯一不同的是,FAT扇區的讀取順序是由DIFAT數組決定的。所以在讀取FAT的時候,需要以此遍歷DIFAT數組,到指定的FAT扇區中讀取FAT數據。

參考代碼如下:

'讀取FAT

Sub ReadFat(FS As Integer, DIFAT() As Long, FAT() As Long, SectorSize As Long)

   Dim i   As Long

   '根據DIFAT的順序。讀取每個FAT扇區

   For i = 0 To UBound(DIFAT)

        ReadFATSector FS, FAT(), DIFAT(i),SectorSize

   Next i

End Sub

 

 

'讀取指定扇區的FAT

Sub ReadFATSector(FS As Integer,FAT() As Long, SectorID As Long, SectorSize As Long)

   Dim i   As Long

   Dim ID  As Long

   '定位

   Seek FS, GetFileOffset(SectorID, SectorSize)

   '讀取FAT。在一個FAT扇區中,有128個FAT數據

   For i = 0 To 127

        '讀取數據

        Get FS, , ID

        '添加至FAT

        AddItem2List FAT, ID

   Next i

End Sub

 

5.7 使用VBA解析MINIFAT

至於解析MINIFAT,留給大家自己完成吧。其方法和FAT類似,其起始扇區ID存放在Header信息中,至於順序嘛,當然是存在FAT中哦,不能搞錯哦。

5.8 小結

本章的內容至關重要,直接關係到能否讀取正確的數據。後面,我將來介紹如何用FAT信息和MINIFAT信息正確讀取數據。

 5.9 示例代碼下載

如果你懶得寫代碼,那麼可以直接下載附件。點擊【閱讀原文】即可。我在文件中準備了兩個不同的文件供測試,一個大的文件是有DIFAT扇區的,一個則沒有。大家可以思考一下,什麼樣的文件纔會有DIFAT扇區?具備DIFAT扇區的文件有什麼特徵呢?

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