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

前端之家收集整理的这篇文章主要介绍了VB快速查找大型文件中包含的字符串前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。


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

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

  1. '使用普通方式查找文件中包含的字符串(返回字符位置)
  2. PrivateFunctionFindText(ByValstrFileNameAsString,ByValstrTextString)Long
  3. DimfnInteger
  4. DimstrFileTextString
  5. DimMyString,MyNumber
  6. DimSString
  7. fn=FreeFile()
  8. OpenstrFileNameForBinaryAs#fn'打开输入文件
  9. strFileText=Input(LOF(fn),fn)
  10. Close#fn
  11. FindText=InStr(strFileText,strText)
  12. EndFunction

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

copy

    SubMain()
  1. DimlStartTime '比较两个方式的运行速度
  2. lStartTime=GetTickCount
  3. CallFindText("G:/Inst/小说/沧海凤歌.txt","打打秋风")'此返回值为字符位置
  4. Debug.PrintGetTickCount-lStartTime
  5. Sub

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

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

copy

    OptionExplicit
  1. DeclareSubCopyMemoryLib"kernel32"Alias"RtlMoveMemory"(DestinationAsAny,SourceByValLengthLong)
  2. FunctionCreateFileAlias"CreateFileA"(ByVallpFileNameByValdwDesiredAccessLong,153); background-color:inherit; font-weight:bold">ByValdwShareModeByVallpSecurityAttributesByValdwCreationDispositionByValdwFlagsAndAttributesByValhTemplateFileLong)FunctionCloseHandleLib"kernel32"(ByValhObjectLong
  3. FunctionGetFileSizeByValhFileConstGENERIC_READ=&H80000000
  4. ConstGENERIC_WRITE=&H40000000
  5. ConstOPEN_EXISTING=3
  6. ConstFILE_SHARE_READ=&H1
  7. ConstFILE_SHARE_WRITE=&H2
  8. ConstFILE_ATTRIBUTE_NORMAL=&H80
  9. ConstFILE_ATTRIBUTE_ARCHIVE=&H20
  10. ConstFILE_ATTRIBUTE_READONLY=&H1
  11. ConstFILE_ATTRIBUTE_HIDDEN=&H2
  12. ConstFILE_ATTRIBUTE_SYSTEM=&H4
  13. FunctionCreateFileMappingAlias"CreateFileMappingA"(ByVallpFileMappigAttributesByValflProtectByValdwMaximumSizeHighByValdwMaximumSizeLowByVallpNameFunctionMapViewOfFileByValhFileMappingObjectByValdwFileOffsetHighByValdwFileOffsetLowByValdwNumberOfBytesToMapFunctionUnmapViewOfFileLib"kernel32"(lpBaseAddressAsAny)ConstPAGE_READWRITE=&H4
  14. ConstFILE_MAP_READ=&H4
  15. FunctionVarPtrArrayLib"msvbvm60.dll"Alias"VarPtr"(Ptr()PrivateTypeSAFEARRAYBOUND
  16. cElements lLboundEndType
  17. PrivateTypeSAFEARRAY1D
  18. cDimsInteger
  19. fFeatures cbElements clocks pvData rgsabound(0)AsSAFEARRAYBOUND
  20. '使用内存映射方式查找大型文件中包含的字符串
  21. FunctionFindTextInFile(DimhFileDimnFileSizeByte
  22. DimppSADimtagNewSAAsSAFEARRAY1D,tagOldSAAsSAFEARRAY1D
  23. hFile=CreateFile(strFileName,_
  24. GENERIC_READOrGENERIC_WRITE,_
  25. FILE_SHARE_READOrFILE_SHARE_WRITE,_
  26. 0,_
  27. OPEN_EXISTING,248); line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important; list-style-position:outside!important"> FILE_ATTRIBUTE_NORMALOrFILE_ATTRIBUTE_ARCHIVEOrFILE_ATTRIBUTE_READONLYOr_
  28. FILE_ATTRIBUTE_HIDDENOrFILE_ATTRIBUTE_SYSTEM,248); line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important; list-style-position:outside!important"> 0)'打开文件
  29. IfhFile<>0Then
  30. nFileSize=GetFileSize(hFile,ByVal0&)'获得文件大小
  31. hFileMap=CreateFileMapping(hFile,PAGE_READWRITE,vbNullString)'创建文件映射对象
  32. lpszFileText=MapViewOfFile(hFileMap,FILE_MAP_READ,0)'将映射对象映射到进程内部的地址空间
  33. ReDimpbFileText(0)'初始化数组
  34. ppSA=VarPtrArray(pbFileText)'获得指向SAFEARRAY的指针的指针
  35. CopyMemorypSA,153); background-color:inherit; font-weight:bold">ByValppSA,4'获得指向SAFEARRAY的指针
  36. CopyMemorytagOldSA,153); background-color:inherit; font-weight:bold">ByValpSA,Len(tagOldSA)'保存原来的SAFEARRAY成员信息
  37. CopyMemorytagNewSA,tagOldSA,Len(tagNewSA)'复制SAFEARRAY成员信息
  38. tagNewSA.rgsabound(0).cElements=nFileSize'修改数组元素个数
  39. tagNewSA.pvData=lpszFileText'修改数组数据地址
  40. CopyMemory'将映射后的数据地址绑定至数组
  41. FindTextInFile=InStr(pbFileText,StrConv(strText,vbFromUnicode))'查找子字符串位置
  42. '恢复数组的SAFEARRAY结构成员信息
  43. ErasepbFileText'删除数组
  44. UnmapViewOfFilelpszFileText'取消地址映射
  45. CloseHandlehFileMap'关闭文件映射对象的句柄
  46. If
  47. CloseHandlehFile'关闭文件
  48. 这个函数明显比上一个函数复杂得到,按理说,它运行速度肯定相应的要慢一些,咱们先不下定论,还是经过测试后再说吧,测试代码如下:

    调用代码如下:

    copy

    lStartTime=GetTickCount
  1. CallFindTextInFile("G:/Inst/小说/沧海凤歌.txt",0); background-color:inherit">'此返回值为字节位置
  2. Debug.PrintGetTickCount-lStartTime
  3. 使用了同一个文本文件,同样测试了20次,嘿,第二个函数最大耗时为17ms,最小耗时为0ms,平均不超过1ms,这进一步验证了我的设计初衷。

    如果你有更好的思路和建议,恳请告诉俺,俺在此表示感谢了!

    原文链接 :http://blog.csdn.net/lyserver/article/details/4106290

    猜你在找的VB相关文章