VB快速查找大型文件中包含的字符串

       关于查找大型文件中包含的字符串,一般都把文件内容读入到内存,然后在内存里进行比较,却不知这种办法有一个致命的弱点,那就是由于大量的内存申请和释放导致的内存颠簸,会使系统性能下降,严重影响了查找的速度。特别是在递归中对多个文件进行查找时,这个问题会更加突出,有时甚至会导致VB程序挂掉。为避免这种情况,同时加快大型文件中字符串的查找速度,俺基于内存影射文件和VB模拟指针技术,编写了一个通用字符串查找函数。

首先,先看一个普通的查找函数: 

代码如下:

'使用普通方式查找文件中包含的字符串(返回字符位置)
Private Function FindText(ByVal strFileName As String, ByVal strText As String) As Long
    Dim fn As Integer
    Dim strFileText As String
   
    Dim MyString, MyNumber
    Dim S As String
   
    fn = FreeFile()
    Open strFileName For Binary As #fn   ' 打开输入文件。
    strFileText = Input(LOF(fn), fn)
    Close #fn
    FindText = InStr(strFileText, strText)
End Function

 用一个400K的文本进行测试,测试次数为20次,测试代码如下:

Sub Main()
    Dim lStartTime As Long

    '比较两个方式的运行速度
    lStartTime = GetTickCount
    Call FindText("G:/Inst/小说/沧海凤歌.txt", "打打秋风") '此返回值为字符位置
    Debug.Print GetTickCount - lStartTime
End Sub

根据测试结果,最大耗时为2050ms,最小耗时为890ms,平均在950ms左右。

然后,我看再看一下基于内存影射和模拟指针的查找函数,代码如下:

Option Explicit

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function GetFileSize Lib "kernel32" (ByVal hFile As Long, lpFileSizeHigh As Long) As Long
Private Const GENERIC_READ = &H80000000
Private Const GENERIC_WRITE = &H40000000
Private Const OPEN_EXISTING = 3
Private Const FILE_SHARE_READ = &H1
Private Const FILE_SHARE_WRITE = &H2
Private Const FILE_ATTRIBUTE_NORMAL = &H80
Private Const FILE_ATTRIBUTE_ARCHIVE = &H20
Private Const FILE_ATTRIBUTE_READONLY = &H1
Private Const FILE_ATTRIBUTE_HIDDEN = &H2
Private Const FILE_ATTRIBUTE_SYSTEM = &H4

Private Declare Function CreateFileMapping Lib "kernel32" Alias "CreateFileMappingA" (ByVal hFile As Long, ByVal lpFileMappigAttributes As Long, ByVal flProtect As Long, ByVal dwMaximumSizeHigh As Long, ByVal dwMaximumSizeLow As Long, ByVal lpName As String) As Long
Private Declare Function MapViewOfFile Lib "kernel32" (ByVal hFileMappingObject As Long, ByVal dwDesiredAccess As Long, ByVal dwFileOffsetHigh As Long, ByVal dwFileOffsetLow As Long, ByVal dwNumberOfBytesToMap As Long) As Long
Private Declare Function UnmapViewOfFile Lib "kernel32" (lpBaseAddress As Any) As Long
Private Const PAGE_READWRITE = &H4
Private Const FILE_MAP_READ = &H4

Private Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (Ptr() As Any) As Long
Private Type SAFEARRAYBOUND
    cElements As Long
    lLbound As Long
End Type
Private Type SAFEARRAY1D
    cDims As Integer
    fFeatures As Integer
    cbElements As Long
    clocks As Long
    pvData As Long
    rgsabound(0) As SAFEARRAYBOUND
End Type

'使用内存映射方式查找大型文件中包含的字符串
Function FindTextInFile(ByVal strFileName As String, ByVal strText As String) As Long
    Dim hFile As Long, hFileMap As Long
    Dim nFileSize As Long, lpszFileText As Long, pbFileText() As Byte
    Dim ppSA As Long, pSA As Long
    Dim tagNewSA As SAFEARRAY1D, tagOldSA As SAFEARRAY1D

    hFile = CreateFile(strFileName, _
            GENERIC_READ Or GENERIC_WRITE, _
            FILE_SHARE_READ Or FILE_SHARE_WRITE, _
            0, _
            OPEN_EXISTING, _
            FILE_ATTRIBUTE_NORMAL Or FILE_ATTRIBUTE_ARCHIVE Or FILE_ATTRIBUTE_READONLY Or _
            FILE_ATTRIBUTE_HIDDEN Or FILE_ATTRIBUTE_SYSTEM, _
            0) '打开文件
    If hFile <> 0 Then
        nFileSize = GetFileSize(hFile, ByVal 0&) '获得文件大小
        hFileMap = CreateFileMapping(hFile, 0, PAGE_READWRITE, 0, 0, vbNullString) '创建文件映射对象
        lpszFileText = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0) '将映射对象映射到进程内部的地址空间
       
        ReDim pbFileText(0) '初始化数组
        ppSA = VarPtrArray(pbFileText) '获得指向SAFEARRAY的指针的指针
        CopyMemory pSA, ByVal ppSA, 4 '获得指向SAFEARRAY的指针
        CopyMemory tagOldSA, ByVal pSA, Len(tagOldSA) '保存原来的SAFEARRAY成员信息
        CopyMemory tagNewSA, tagOldSA, Len(tagNewSA) '复制SAFEARRAY成员信息
        tagNewSA.rgsabound(0).cElements = nFileSize '修改数组元素个数
        tagNewSA.pvData = lpszFileText '修改数组数据地址
        CopyMemory ByVal pSA, tagNewSA, Len(tagNewSA) '将映射后的数据地址绑定至数组
       
        FindTextInFile = InStr(pbFileText, StrConv(strText, vbFromUnicode)) '查找子字符串位置
       
        CopyMemory ByVal pSA, tagOldSA, Len(tagOldSA) '恢复数组的SAFEARRAY结构成员信息
        Erase pbFileText '删除数组
       
        UnmapViewOfFile lpszFileText '取消地址映射
        CloseHandle hFileMap '关闭文件映射对象的句柄
    End If
    CloseHandle hFile '关闭文件
End Function

这个函数明显比上一个函数复杂得到,按理说,它运行速度肯定相应的要慢一些,咱们先不下定论,还是经过测试后再说吧,测试代码如下:

调用代码如下: 

Sub Main()
    lStartTime = GetTickCount
    Call FindTextInFile("G:/Inst/小说/沧海凤歌.txt", "打打秋风") '此返回值为字节位置
    Debug.Print GetTickCount - lStartTime
End Sub

 

摘自:VB快速查找大型文件中包含的字符串

 
  

VB相关


VB 释放资源文件到指定目录函数

VB 读取资源文件里面的字符串

VB中资源文件.res的使用方法详解

VB6.0中创建和使用文本资源文件

VB WindowsMediaPlayer 播放

vbWindowsMediaPlayer的常用属性和方法

VB Environ系统环境变量函数大全

VB 去除文本框粘贴功能

VB LISTBOX

VB 删除数组中的重复元素

VB数组快速排序算法

关于三个概念:ActiveXOLECOM

VB 获得磁盘的文件系统

VB中用API实现文件拖放

加密算法-MD5算法

VB中使用MD5算法

VB 全局热键HOOK (不占系统资源版本)

VB 小技巧自定义TextBox文本框右键菜单

VB 写下载者代码

VB 一行代码的诀窍

VBS教程-wscript对象

vb枚举进程

VB中如何让线程或进程在指定的CPU上运行

VB判断指定的WORD文档是否被打开

VB如何读取快捷方式的目标路径

VBAPI控制输入法状态

为系统加载右键注册控件选项【VB 注册控件】

VB如何根据窗口标题获得进程名称

VB快速查找大型文件中包含的字符串

VB实现可执行文件运行时自删除

VB 打开txt,bat,jpg 任意后缀程序

VB 写文件关联程序

VB 自启动建立右键菜单

VB 判断IP能否ping

VB FTP操作类(可上传、下载、创建文件夹等等)

VB部分文件汇总B

Vb 求素数最经典的方法也是最快的方法

vb用数组方式快速导出MSFlexGrid表格数据到Excel表格中

VBMsFlexGrid控件的使用细则

点击MSFlexGrid数据控件的标题进行数据排序

VB 获取鼠标坐标

VBNEW的用法(申请内存空间)

VB CreateObject函数

VB中的New CreateObject的区别

VB ListBox 添加不重复的值

VB 单击ListView控件某列表头进行排序

VB 简单实现简体与繁体互转

VB 阿拉伯数字转换为中文大写数值函数

VB 获取Textbox文本框中的行数函数


更多精彩>>>
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

miaozk2006

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值