复合文档格式研究之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  小结

到这里为止,我们已经掌握了解析文件所需要的基本编程知识。接下去,让我们一起开始解析一下文件吧。

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