李懿 Excel學習 2016-07-05
微信掃一掃
關注該公衆號
複合文檔的解析基礎
終於要開始寫程序了,不過在正式解析Excel文件之前,我們先來學習一點預備知識。
3.1 自定義數據類型
在VBA中,有一個自定義的數據類型,在其內部可以包含幾個不同的類型的數據。其聲明的語法如下:
[Private | Public] Type 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中與文件讀取的相關方法
首先我們來介紹一下使用到的幾個方法:
-
Open方法。該方法用於打開文件,打開後可以得到一個特殊的編號,之後再讀取文件的數據都需要該編號。
-
FreeFile函數。
-
Get方法。使用Open方法打開文件後,該方法可以按字節讀取數據。
-
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 BZ與VBA數據讀取對比
可以發現:
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 小結
到這裏爲止,我們已經掌握瞭解析文件所需要的基本編程知識。接下去,讓我們一起開始解析一下文件吧。