关于查找大型文件中包含的字符串,一般都把文件内容读入到内存,然后在内存里进行比较,却不知这种办法有一个致命的弱点,那就是由于大量的内存申请和释放导致的内存颠簸,会使系统性能下降,严重影响了查找的速度。特别是在递归中对多个文件进行查找时,这个问题会更加突出,有时甚至会导致VB程序挂掉。为避免这种情况,同时加快大型文件中字符串的查找速度,俺基于内存影射文件和VB模拟指针技术,编写了一个通用字符串查找函数。
首先,先看一个普通的查找函数:
-
- PrivateFunctionFindText(ByValstrFileNameAsString,ByValstrTextString)Long
- DimfnInteger
- DimstrFileTextString
-
- DimMyString,MyNumber
- DimSString
-
- fn=FreeFile()
- OpenstrFileNameForBinaryAs#fn
- strFileText=Input(LOF(fn),fn)
- Close#fn
- FindText=InStr(strFileText,strText)
- EndFunction
用一个400K的文本进行测试,测试次数为20次,测试代码如下:
copy
SubMain()
- DimlStartTime
- lStartTime=GetTickCount
- CallFindText("G:/Inst/小说/沧海凤歌.txt","打打秋风")
- Debug.PrintGetTickCount-lStartTime
- Sub
根据测试结果,最大耗时为2050ms,最小耗时为890ms,平均在950ms左右。
然后,我看再看一下基于内存影射和模拟指针的查找函数,代码如下:
copy
OptionExplicit
- DeclareSubCopyMemoryLib"kernel32"Alias"RtlMoveMemory"(DestinationAsAny,SourceByValLengthLong)
- FunctionCreateFileAlias"CreateFileA"(ByVallpFileNameByValdwDesiredAccessLong,153); background-color:inherit; font-weight:bold">ByValdwShareModeByVallpSecurityAttributesByValdwCreationDispositionByValdwFlagsAndAttributesByValhTemplateFileLong)FunctionCloseHandleLib"kernel32"(ByValhObjectLong
- FunctionGetFileSizeByValhFileConstGENERIC_READ=&H80000000
- ConstGENERIC_WRITE=&H40000000
- ConstOPEN_EXISTING=3
- ConstFILE_SHARE_READ=&H1
- ConstFILE_SHARE_WRITE=&H2
- ConstFILE_ATTRIBUTE_NORMAL=&H80
- ConstFILE_ATTRIBUTE_ARCHIVE=&H20
- ConstFILE_ATTRIBUTE_READONLY=&H1
- ConstFILE_ATTRIBUTE_HIDDEN=&H2
- ConstFILE_ATTRIBUTE_SYSTEM=&H4
- FunctionCreateFileMappingAlias"CreateFileMappingA"(ByVallpFileMappigAttributesByValflProtectByValdwMaximumSizeHighByValdwMaximumSizeLowByVallpNameFunctionMapViewOfFileByValhFileMappingObjectByValdwFileOffsetHighByValdwFileOffsetLowByValdwNumberOfBytesToMapFunctionUnmapViewOfFileLib"kernel32"(lpBaseAddressAsAny)ConstPAGE_READWRITE=&H4
- ConstFILE_MAP_READ=&H4
- FunctionVarPtrArrayLib"msvbvm60.dll"Alias"VarPtr"(Ptr()PrivateTypeSAFEARRAYBOUND
- cElements lLboundEndType
- PrivateTypeSAFEARRAY1D
- cDimsInteger
- fFeatures cbElements clocks pvData rgsabound(0)AsSAFEARRAYBOUND
- '使用内存映射方式查找大型文件中包含的字符串
- FunctionFindTextInFile(DimhFileDimnFileSizeByte
- DimppSADimtagNewSAAsSAFEARRAY1D,tagOldSAAsSAFEARRAY1D
- hFile=CreateFile(strFileName,_
- GENERIC_READOrGENERIC_WRITE,_
- FILE_SHARE_READOrFILE_SHARE_WRITE,_
- 0,_
- 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_
- FILE_ATTRIBUTE_HIDDENOrFILE_ATTRIBUTE_SYSTEM,248); line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important; list-style-position:outside!important"> 0)
- IfhFile<>0Then
- nFileSize=GetFileSize(hFile,ByVal0&)
- hFileMap=CreateFileMapping(hFile,PAGE_READWRITE,vbNullString)
- lpszFileText=MapViewOfFile(hFileMap,FILE_MAP_READ,0)
- ReDimpbFileText(0)
- ppSA=VarPtrArray(pbFileText)
- CopyMemorypSA,153); background-color:inherit; font-weight:bold">ByValppSA,4
- CopyMemorytagOldSA,153); background-color:inherit; font-weight:bold">ByValpSA,Len(tagOldSA)
- CopyMemorytagNewSA,tagOldSA,Len(tagNewSA)
- tagNewSA.rgsabound(0).cElements=nFileSize
- tagNewSA.pvData=lpszFileText
- CopyMemory'将映射后的数据地址绑定至数组
- FindTextInFile=InStr(pbFileText,StrConv(strText,vbFromUnicode))
- '恢复数组的SAFEARRAY结构成员信息
- ErasepbFileText
- UnmapViewOfFilelpszFileText
- CloseHandlehFileMap
- If
- CloseHandlehFile
- 这个函数明显比上一个函数复杂得到,按理说,它运行速度肯定相应的要慢一些,咱们先不下定论,还是经过测试后再说吧,测试代码如下:
调用代码如下:
copy
lStartTime=GetTickCount
- CallFindTextInFile("G:/Inst/小说/沧海凤歌.txt",0); background-color:inherit">'此返回值为字节位置
- Debug.PrintGetTickCount-lStartTime
- 使用了同一个文本文件,同样测试了20次,嘿,第二个函数最大耗时为17ms,最小耗时为0ms,平均不超过1ms,这进一步验证了我的设计初衷。
如果你有更好的思路和建议,恳请告诉俺,俺在此表示感谢了!
原文链接 :http://blog.csdn.net/lyserver/article/details/4106290 (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|