複合文檔格式研究之03-用VBA讀取文件

李懿 Excel學習 2016-07-05

 

微信掃一掃
關注該公衆號

複合文檔的解析基礎

終於要開始寫程序了,不過在正式解析Excel文件之前,我們先來學習一點預備知識。

 

3.1 自定義數據類型

在VBA中,有一個自定義的數據類型,在其內部可以包含幾個不同的類型的數據。其聲明的語法如下:

[Private | PublicType varname
    elementname [([subscripts])As type
    [elementname [([subscripts])As type]
    . . .

End Type

舉個簡單的例子:

 

Type MyType

    ValA As Long

    ValB As String

    ValC As Byte

    ValD As Double

    ValE As Integer

End Type

 

上述示例聲明瞭一個名爲MyType的自定義類型的數據,其中包含了ValA,ValB等5個元素的數據。MyType可以直接作爲一種數據類型使用,並且可以每個元素都可以單獨進行訪問。


 13         自定義類型的使用

其元素的使用和一般變量的使用方法一致。

使用自定義數據類型的好處就是,在變量內部的各個元素的存儲位置都是連續的,這樣就可以很方便地獲取複合文檔中的各個內容。通過VarPtr函數可以獲取變量的地址。我們來測試一下以下代碼:

 

Sub Test()

    Dim MyTypeV As MyType

    Debug.Print VarPtr(MyTypeV.ValA)

    Debug.Print VarPtr(MyTypeV.ValB)

    Debug.Print VarPtr(MyTypeV.ValC)

    Debug.Print VarPtr(MyTypeV.ValD)

    Debug.Print VarPtr(MyTypeV.ValE)

End Sub

查看立即窗口的輸出

 14         自定義類型各個元素的地址示例

ValA是一個4字節的Long類型的數據,所以第二個元素ValB留下了預留的4個字節的存儲空間,ValB的地址恰好比ValA的地址大4個字節。對其他字段驗證的結果也是如此。

 

3.2 VBA中與文件讀取的相關方法

首先我們來介紹一下使用到的幾個方法:

  1. Open方法。該方法用於打開文件,打開後可以得到一個特殊的編號,之後再讀取文件的數據都需要該編號。

  2. FreeFile函數。

  3. Get方法。使用Open方法打開文件後,該方法可以按字節讀取數據。

  4. Seek方法。使用Open方法打開文件後,該方法可以用於定位指定的文件位置(即地址)。

     

3.3 數據存儲

我們的Excel的數據存儲,使用了一種叫做Little Endian的方式,即低位優先的方式。

我們知道,在計算機中的數據存儲單位是字節,一個字節是一個8爲的二進制數據,存儲數據的範圍是2的8次方,也就是0-255的無符號數字。爲了方便,一般使用2個十六進制數據表示一個字節。比如十進制的255可以用十六進制數FF表示,十進制的32可以用十六進制數20表示。

爲了方便比對,我使用了一個名爲Binary Editor的二進制編輯軟件。使用該軟件打開我們的測試文件。


 15         文件數據示例

這張圖裏面的所有的數據都是16進制的,最左側的000000和000010表示這一行數據的起始地址,每一行相差16個字節。最上方的0~F表示偏移量,同一行每一列中相差一個字節。中間的數據爲每個字節存放的數據。

我們來看第二行3E那個數據,它處在000010的行,在+8列下,表示這個地址的真實地址是000018。(注意:中間的那個-不是減號或者負號,只是表示8個字節的分割,方便大家看而已)

我們看最開始的兩個字節的數據D0和CF,如果把這兩個字節的數據按順序來表示,可以組合成一個十六進制數D0CF,它表示了一個有符號(即有正負的)數-12081,或者一個無符號(即只有正數)數53455。這樣的存儲方式稱爲Big Endian(BE)。

然而,Excel中是以Little Endian(LE)存儲的。它和BE的方式正好相反,是一個倒序的存儲。最開始的兩位字節表示的是CFD0,也就是-12336。恰好,我們VBA讀取也是LE的方式的,因而完全不用擔心會搞錯。

 

3.3 數據讀取

下面我們就來驗證一下數據,創建一個文件,[Alt+F11]打開VBE,添加一個模塊,錄入以下代碼:

 

Sub OpenFileTesting()

    Dim FS      As Integer  'File No.

    Dim Val1    As Integer

    Dim Val2(1) As Byte

    Dim Val3(2) As Integer

    FS = FreeFile           '獲取一個文件流

    '打開文件

    Open ThisWorkbook.Path & "\test.xls" For Binary Access Read As FS

    '順序讀取數據至3個變量

    Get FS, , Val1

    Get FS, , Val2

    Get FS, , Val3

    Close FS                '關閉文件流

    Stop

End Sub

然後打開“本地窗口”


 16         VBA讀取文件結果

爲了方便起見,我把這些數字都換成了十六進制。然後和最初我們用BZ讀取的文件數據來對比一下。


 17         BZVBA數據讀取對比

可以發現:

1、VBA每讀取一次數據,再次讀取時是會接着當前位置讀取下一個數據的。

2、VBA讀取的字節數按照變量類型所佔用的字節數讀取,比如Integer讀取兩個字節,Byte讀取一個字節。

3、每個變量在解析值的時候都是按照LE的規則。

4、數組按照文件順序讀取數據順序存儲給數組的各個元素。

然後我們利用自定義類型再來試試,新建一個模塊,錄入以下代碼並運行:

 

Type MyFileType

    Val1    As Integer

    Val2(1) As Byte

    Val3(2) As Integer

End Type

Sub OpenFileTesting2()

    Dim FS      As Integer  'File No.

    Dim Val     As MyFileType

    FS = FreeFile           '獲取一個文件流

    '打開文件

    Open ThisWorkbook.Path & "\test.xls" For Binary Access Read As FS

    '讀取數據至自定義類型

    Get FS, , Val

    Close FS                '關閉文件流

    Stop

End Sub

 

打開“本地窗口”查看一下:


 18 讀取文件至自定義數據類型

看到了什麼?是不是和之前分別讀取一樣的效果?

 

3.4  小結

到這裏爲止,我們已經掌握瞭解析文件所需要的基本編程知識。接下去,讓我們一起開始解析一下文件吧。

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