如何在多个文件中查找需要的信息
1. 问题描述
现在的信息系统,虽然很多都是使用数据库保存其信息,因此,内容的搜索查找实现一般都比较容易,但也有部分系统,或者某些情况需要在一些文件中查找需要的信息。
本文需要解决的问题就是这样一个问题。有一系列相同格式的2进制文件,压缩保存在不同的文件中,此二进制文件可以应用一个通用程序转化为相同文本文件(如下所示);
###### ###### ###### ###### ######
###### ###### ###### ###### ######
…
现在需要编制一个程序从这些文件中查找符合某些条件的行,然后保存在另一个文本文件中。
2. 解决思路
对于这样的问题,我不知道别人会怎么做,要是以前,自己肯定会自然而然的想着使用C或者C++做(因为这是自己最先学习的编程语言),或者使用VB开发(比较熟悉),而考虑如何设计一个文件读取功能,如何将文件内容保存在一个数组或者其他数据结构中,如何设计查找算法,等等。
或者可以考虑使用一个简单的桌面数据库,将数据全部读入数据库,然后再进行操作。
本文介绍的方法是使用Microsoft Excel + VBA实现所需要的功能,原因如下:
- 文件读取等操作可以交给Excel去做;
- 数据可以自然的保存在Excel中;
- 查询可以调用Excel的方法,也可以自己写一个简单的顺序查找。
对于使用Excel,可以有两种考虑,或者使用VB或者其他支持COM自动化的程序调用Excel,或者在Excel中使用VBA编写需要的代码,在Excel下执行。前者可以在其他程序中嵌入使用,而Excel可以完全在后台执行,后者无需其他程序开发环境,选取完全取决于要求。
因此,程序的流程大概为:
1) 调用外部程序解压缩并转化相应的文件;
2) 逐个打开转换后的文本文件,在Excel中查找;
3) 完成操作,清理。
3. 关键代码
3.1. 调用外部程序
在VBA中,同VB一样,调用外部程序的函数为“Shell”。
Shell(pathname[,windowstyle]):
执行一个可执行文件,返回一个 Variant (Double),如果成功的话,代表这个程序的任务 ID,若不成功,则会返回 0。Shell 函数是以异步方式来执行其它程序的。也就是说,用 Shell 启动的程序可能还没有完成执行过程,就已经执行到 Shell 函数之后的语句。
对于需要同步执行的程序,可以使用以下代码:
Private Declare Function WaitForSingleObject Lib "kernel32" _
(ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" _
(ByVal hObject As Long) As Long
Private Declare Function OpenProcess Lib "kernel32" _
(ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, _
ByVal dwProcessId As Long) As Long
Private Const INFINITE = -1&
Private Const SYNCHRONIZE = &H100000
Private Sub ShellTest()
Dim iTask As Long, ret As Long, pHandle As Long
iTask = Shell("notepad.exe", vbNormalFocus) ‘开始执行
pHandle = OpenProcess(SYNCHRONIZE, False, iTask)
ret = WaitForSingleObject(pHandle, INFINITE)
ret = CloseHandle(pHandle) ‘执行结束
MsgBox "Process Finished!"
End Sub
3.2. 文件操作
程序使用的文件操作包括如何打开文件、关闭文件,在打开的文件之间切换等操作。
打开文件:
Application.Workbooks.OpenText 用于打开文本文件
Application.Workbooks.Open 用于打开Excel文件
对于文件打开操作,可以使用宏录制功能,以便实现格式转化,定制列的格式等操作。
关闭文件:
Application.Workbooks(文件名).Close 关闭文件
Close方法参数可以是True或者False,分别表示是否保存文件。
切换当前文件:
Application.Workbooks(文件名). Activate
需要注意的是,使用Workbooks集合返回Workbook对象时,使用的文件名必须是不包括路径但包括扩展名的文件名,例如“abc.txt”,或者“xyz.xls”。
3.3. 查询操作的实现
逐个打开各个文件,就可以进行查询操作了,查询结果可以写入一个临时的Excel文件,然后保存之。
查询操作可以调用Excel的函数实现,Excel有数十个查找引用函数,例如HLookUP,VLookUP等,在VBA中使用这些函数的方法是,Application.函数名。
对于本文的情况,可以直接编写一个顺序查找,要获取各个单元格的值,最简单的方法就是使用Range对象,例如,Range(“A1”).Value,返回当前工作表活动Sheet,单元格A1的值。对于有多个打开工作表的情况,可以使用Windows(文件名).Sheets().Range,或者Workbooks(文件名). .Sheets().Range来获得Range对象。
需要说明的是,使用Range对象虽然方便,可控制性强,但Range对象的操作是非常耗时的一项操作,最好不要频繁访问,具体优化方法可以通过转化为数组等操作来进行,有兴趣者可参考笔者的“在Excel中使用VBA来筛选数据”一文(http://www.cnblogs.com/maweifeng/archive/2004/12/01/71504.html)。
一般来说,可以直接调用Excel函数和功能的,最好调用其实现,因为效率和速度都相对比使用VBA完成的代码要好。
3.4. 编写界面
在Excel下,一个VBA程序的发布形式有2种,基于Excel文件发布或者发布为一个Excel加载宏程序。对于应用界面,可以在Excel已有的菜单、工具条上增加新的内容,也可以直接在Excel图表中增加控件,或者使用自定义窗体,不同的方式有不同的应用领域。
对于增加的工具条和按钮等界面内容,一般的编程方式是,当你的加载宏或者Excel文件打开运行时,将界面内容增加到Excel中,而结束或退出时,删除其内容,因此相关代码一般写在VBA项目(工程)的ThisWookbook对象下,在此对象中,选择Workbook_Open,以及Workbook_BeforeClose事件,在其中添加工具按钮的增加,删除操作;对于加载宏,有Workbook_AddinInstall,Workbook_AddinUninstall事件。
4. 总结
使用VBA和Excel实现在多个文件中查找所需要的数据,相对于使用其他编程语言直接编写实现,要高效迅速的多,而且程序的可维护性也好很多,因此,在可以利用Office等已有资源的时候,应该优先考虑使用此类资源实现程序的有关功能。
浙公网安备 33010602011771号