Excel VBA 编程基础 -- 文件处理(七)
前面我们讨论了文本文件的打开、读写、关闭。今天讨论对二进制文件的处理。所谓二进制文件(binary file),是指文件内容以二进制形式存储、人不可识别而至用于机器读写的文件。相反,文本文件(text file),则是指文件内容以文本形式存储、人可识别的文件。一般而言,文本文件主要用于存储最终结果,或者用于跨平台网络传输,如 XML、json、CSV 文件。二进制文件则主要用来存储数据以用于程序读写。相应于用来读写文本文件的 Print # / Write # 和 Input # / Line Input # 语句,用于二进制文件的读写语句分别是 Get 和 Put。Get 用于读取文件中的数据并赋给变量。其一般格式是:Get [#]filenumber, [recnumber], varname其中,filenumber 是用来读取数据的文件号。可选参数 recnumber 是 Variant(Long) 类型。对于 Random 模式,recnumbe 是记录号,对于 Binary 模式,recnumber 则是下一个要读取的数据在文件中的字节序号。varname 是接受数据的变量名。Put 用于将变量中的数据写入二进制文件。其一般格式是:Put [#]filenumber, [recnumber], varname其中,filenumber 是用来写入数据的文件号。可选参数 recnumber 是 Variant(Long) 类型。对于 Random 模式,recnumbe 是记录号,对于 Binary 模式,recnumber 则是下一个要写入的数据在文件中的字节序号。varname 是存有要写入文件数据的变量名。为了更好地理解 Get / Put 语句各参数的意义,我们把 Open 语句的格式再温习一下。这里,我们不考虑用于多进程读写文件的 lock 参数。只看 For、Access 和 Len 参数:- Formode:For 用来表达“打开文件要做什么”,这个“做什么”由 mode 指定:
- Input:表示打开文件用来读取数据,意味着“只读”,且文件必须存在。
- Output:表示打开文件用来写入数据,意味着“只写”,若文件不存在,则创建之。
- Append:表示打开文件用来追加数据,也意味着“只写”,但与 Output 不同,Append 要求文件必须存在。
- Binary:表示打开文件用来存取二进制数据,意味着“读写”,如果文件不存在,则创建之。
- Random:表示打开文件用来随机存取文件中的数据,也意味着“读写”,如果文件不存在,则创建之。
- Accessaccess:Access 进一步表示对文件的访问方式,其“访问方式”由 access 指定:
- Len = reclength:Len 参数用来指定记录长度或读取/写入的缓冲区长度,具体数值由 reclength 给出:
- 对于 Binary mode:reclength 参数用来指定缓冲区的长度
- 对于 Random mode:reclength 参数用来指定记录长度
Access access 一般来说只用于 Binary 或 Random 模式,对于 Input、Output、Append 模式,因为其本身已经指定了输入/输出方向,已不再需要 Access 进一步指定。而对于 Binary 或 Random 模式,因为其本身指定的是读和写,因此有必要用 Access 再进一步规范只读、只写、读写三种具体的输入/输出方向。注:VBA 的 Open 语句之所以有这样似乎比较繁琐的表示方式,是为了最大限度地向其他进程提供共享的可能性。譬如,你打开一个大型的二进制数据文件,如果不指定 Access,则默认该文件是读写,此时其他进程无法访问该文件,如果你仅仅是用来读取,则浪费了其他进程的等待时间。如果指定 Access Read,则其他进程可以根据你指定的 lock 参数来访问该文件。在这个例子中,我们首先打开文件用于二进制输出,因此在 Open 语句上指定了 For Binary Access Write,且指定了 Len = diSize = Len(di) = Len(Long),即指定了读取 / 写入二进制文件中的数据项的长度。因为我们是向文件 hello.dat 写入一系列的 Long 型整数,因此 Len = Len(Long) 表示 Long 整数在内存中所占用的字节数(Long 型是 32 位整数,占用 4 个字节)。然后进入一个 For 循环,由 Put 语句向文件中写入一系列数据。注意 Put 语句的 recnumber 参数,例中指定了 i * diSize + 1,表示 Put 在写入 di 时在文件中的位置:i = 0 时,其值是 1,表示 Put 将 di 写入第一个位置;i = 1 时,其值是 5,表示此时 Put 要将 di 写入第 5 个位置(因为前面 4 个位置已经写入了上一个 di),以此类推。接下来,重新打开文件用于输入。Open 语句的参数分别是 For Binary Access Read,且 Len 参数与只写时 Open 语句中指定的相同。注:如果此时指定的 Len 不同于前一个 Open 语句中的 Len,会发生什么情况?接下来又是一个 For 循环,此时用 Get 来读取文件中的数据。可以看到,Get 语句所使用参数与前面 Put 语句使用的参数相同。此例中,在读写时都给出了追踪信息,可以在右边的立即窗口中看到,写入和读取的数据是一样的,其中前缀以 &H 的是数据的二进制表示。对照图2 和图1 的立即窗口,可以看出,第一个数据项是 &H00000033 = &H33 = 51,第二个数据项是 &H00000034 = &H34 = 52,以此类推。注:图2 所示的数据 33 00 00 00,是因为 Intel CPU 使用的是小端序,即低位字节在前的表示方式,对于使用大端序的 CPU,其数据表示将是 00 00 00 33。这只是数据内部表示方式的不同,其表示的数据值是一样的。