数据查找问题请教

xingmin 2015-01-12 10:59:40
我在网上找大数据文件下的快速查找,找到lyserver发表的文章VB快速查找大型文件中包含的字符串 链接http://blog.csdn.net/lyserver/article/details/4106290
发现有问题,即函数FindTextInFile无法正确返回查找的字符串信息,所有结果都是返回0


以下为代码,请教高手修正一下问题,可以正确返回查找结果


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
...全文
239 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
xingmin 2015-01-23
  • 打赏
  • 举报
回复
没有人可以帮忙修改代码吗
赵4老师 2015-01-23
  • 打赏
  • 举报
回复
C:\>findstr /? 在文件中寻找字符串。 FINDSTR [/B] [/E] [/L] [/R] [/S] [/I] [/X] [/V] [/N] [/M] [/O] [/F:file] [/C:string] [/G:file] [/D:dir list] [/A:color attributes] [/OFF[LINE]] strings [[drive:][path]filename[ ...]] /B 在一行的开始配对模式。 /E 在一行的结尾配对模式。 /L 按字使用搜索字符串。 /R 将搜索字符串作为一般表达式使用。 /S 在当前目录和所有子目录中搜索匹配文件。 /I 指定搜索不分大小写。 /X 打印完全匹配的行。 /V 只打印不包含匹配的行。 /N 在匹配的每行前打印行数。 /M 如果文件含有匹配项,只打印其文件名。 /O 在每个匹配行前打印字符偏移量。 /P 忽略有不可打印字符的文件。 /OFF[LINE] 不跳过带有脱机属性集的文件。 /A:attr 指定有十六进位数字的颜色属性。请见 "color /?" /F:file 从指定文件读文件列表 (/ 代表控制台)。 /C:string 使用指定字符串作为文字搜索字符串。 /G:file 从指定的文件获得搜索字符串。 (/ 代表控制台)。 /D:dir 查找以分号为分隔符的目录列表 strings 要查找的文字。 [drive:][path]filename 指定要查找的文件。 除非参数有 /C 前缀,请使用空格隔开搜索字符串。 例如: 'FINDSTR "hello there" x.y' 在文件 x.y 中寻找 "hello" 或 "there"。'FINDSTR /C:"hello there" x.y' 文件 x.y 寻找 "hello there"。 一般表达式的快速参考: . 通配符: 任何字符 * 重复: 以前字符或类别出现零或零以上次数 ^ 行位置: 行的开始 $ 行位置: 行的终点 [class] 字符类别: 任何在字符集中的字符 [^class] 补字符类别: 任何不在字符集中的字符 [x-y] 范围: 在指定范围内的任何字符 \x Escape: 元字符 x 的文字用法 \<xyz 字位置: 字的开始 xyz\> 字位置: 字的结束 有关 FINDSTR 常见表达法的详细情况,请见联机命令参考。 C:\>
一如既往哈 2015-01-13
  • 打赏
  • 举报
回复
呵呵,我可不想整那么复杂,来个简单的,速度也不会太慢的,请参考下面的代码:
Option Explicit
Sub Test()
    Dim iNum As Integer, i As Long, s1 As String, k As Long
    Dim j As Long, Byt() As Byte, m As Long, n As Single, p As Integer
    Dim ff As String, ffByt() As Byte, fLen As Integer, bTr As Boolean
    s1 = "e:\电影\黑暗生物\VTS_03_1.VOB" ''这里要改成你的大文件地址
    ff = "abcdefg" ''这里要改成你要查找的字符串
    ffByt = StrConv(ff, vbFromUnicode)
    fLen = UBound(ffByt) + 1
    iNum = FreeFile() ''
    k = 10000 ''10k
    n = Timer ''
    ReDim Byt(k + UBound(ffByt))
    Open s1 For Binary As #iNum
    For i = 1 To LOF(iNum) Step k
        If i + k + fLen > LOF(iNum) Then
            ReDim Byt(LOF(iNum) - i)
        End If
        Get #iNum, i, Byt
        For j = 0 To UBound(Byt) - fLen + 1
            If Byt(j) = ffByt(0) Then
                If Byt(j + 1) = ffByt(1) Then
                    bTr = True
                    For p = 2 To fLen - 1
                        If Byt(j + p) <> ffByt(p) Then
                            bTr = False
                            Exit For
                        End If
                    Next
                    If bTr Then
                        m = i + j
                        GoTo 100
                    End If
                End If
            End If
        Next
    Next
100:
    Debug.Print IIf(m > 0, "位置:" & m, "很遗憾!没找到!") & ",耗时>>" & (Timer - n)
    Close #iNum
End Sub


一如既往哈 2015-01-13
  • 打赏
  • 举报
回复
有必要弄得那么复杂么? 打开文件,每次读10k,然后从这10k里搜查字符,搜完后再读10k......,如此循环往复,管它文件是1G,还是1T,照样操作,只是时间有长有段而已。 有一点要注意:块与块的衔接处要有一点小技巧,否则有可能找不到的。
xingmin 2015-01-13
  • 打赏
  • 举报
回复
引用 1 楼 Topc008 的回复:
有必要弄得那么复杂么? 打开文件,每次读10k,然后从这10k里搜查字符,搜完后再读10k......,如此循环往复,管它文件是1G,还是1T,照样操作,只是时间有长有段而已。 有一点要注意:块与块的衔接处要有一点小技巧,否则有可能找不到的。
可以对这个代码修改一下吗

7,763

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧