使用VBA操作文件(12):如何使用VBA查找文件
下面的代码主要介绍如何使用Windows API函数及内置的VBA函数查找和列出文件。当然,VBA也包含了用于查找和列出文件的Application.FileSearch对象。
方法1:使用Windows API
步骤1 在VBE中,插入一个标准模块,并输入下面的代码:
Declare Function FindFirstFile Lib "kernel32" Alias _ "FindFirstFileA" (ByVal lpFileName As String, lpFindFileData _ As WIN32_FIND_DATA) As Long Declare Function FindNextFile Lib "kernel32" Alias "FindNextFileA" _ (ByVal hFindFile As Long, lpFindFileData As WIN32_FIND_DATA) As Long Declare Function GetFileAttributes Lib "kernel32" Alias _ "GetFileAttributesA" (ByVal lpFileName As String) As Long Declare Function FindClose Lib "kernel32" (ByVal hFindFile As Long) _ As Long Declare Function FileTimeToLocalFileTime Lib "kernel32" _ (lpFileTime As FILETIME, lpLocalFileTime As FILETIME) As Long Declare Function FileTimeToSystemTime Lib "kernel32" _ (lpFileTime As FILETIME, lpSystemTime As SYSTEMTIME) As Long Public Const MAX_PATH = 260 Public Const MAXDWORD = &HFFFF Public Const INVALID_HANDLE_VALUE = -1 Public Const FILE_ATTRIBUTE_ARCHIVE = &H20 Public Const FILE_ATTRIBUTE_DIRECTORY = &H10 Public Const FILE_ATTRIBUTE_HIDDEN = &H2 Public Const FILE_ATTRIBUTE_NORMAL = &H80 Public Const FILE_ATTRIBUTE_READONLY = &H1 Public Const FILE_ATTRIBUTE_SYSTEM = &H4 Public Const FILE_ATTRIBUTE_TEMPORARY = &H100 Type FILETIME dwLowDateTime As Long dwHighDateTime As Long End Type Type WIN32_FIND_DATA dwFileAttributes As Long ftCreationTime As FILETIME ftLastAccessTime As FILETIME ftLastWriteTime As FILETIME nFileSizeHigh As Long nFileSizeLow As Long dwReserved0 As Long dwReserved1 As Long cFileName As String * MAX_PATH cAlternate As String * 14 End Type Type SYSTEMTIME wYear As Integer wMonth As Integer wDayOfWeek As Integer wDay As Integer wHour As Integer wMinute As Integer wSecond As Integer wMilliseconds As Integer End Type Public Function StripNulls(OriginalStr As String) As String If (InStr(OriginalStr, Chr(0)) > 0) Then OriginalStr = Left(OriginalStr, _ InStr(OriginalStr, Chr(0)) - 1) End If StripNulls = OriginalStr End Function
步骤2 在VBE中插入一个用户窗体,如下图所示。

如图所示,在用户窗体中,放置4个文本框(分别名为TextBox1、TextBox2、TextBox3、TextBox4),1个命令按钮(名为CommandButton1),1个列表框(名为ListBox1)。
步骤3 在用户窗体代码模块中,添加下列代码:
Function FindFilesAPI(path As String, SearchStr As String, _ FileCount As Integer, DirCount As Integer) Dim FileName As String ' Walking filename variable... Dim DirName As String ' SubDirectory Name Dim dirNames() As String ' Buffer for directory name entries Dim nDir As Integer ' Number of directories in this path Dim i As Integer ' For-loop counter... Dim hSearch As Long ' Search Handle Dim WFD As WIN32_FIND_DATA Dim Cont As Integer Dim FT As FILETIME Dim ST As SYSTEMTIME Dim DateCStr As String, DateMStr As String If Right(path, 1) <> "\" Then path = path & "\" ' Search for subdirectories. nDir = 0 ReDim dirNames(nDir) Cont = True hSearch = FindFirstFile(path & "*", WFD) If hSearch <> INVALID_HANDLE_VALUE Then Do While Cont DirName = StripNulls(WFD.cFileName) ' Ignore the current and encompassing directories. If (DirName <> ".") And (DirName <> "..") Then ' Check for directory with bitwise comparison. If GetFileAttributes(path & DirName) And _ FILE_ATTRIBUTE_DIRECTORY Then dirNames(nDir) = DirName DirCount = DirCount + 1 nDir = nDir + 1 ReDim Preserve dirNames(nDir) ' Uncomment the next line to list directories 'List1.AddItem path & FileName End If End If Cont = FindNextFile(hSearch, WFD) ' Get next subdirectory. Loop Cont = FindClose(hSearch) End If ' Walk through this directory and sum file sizes. hSearch = FindFirstFile(path & SearchStr, WFD) Cont = True If hSearch <> INVALID_HANDLE_VALUE Then While Cont FileName = StripNulls(WFD.cFileName) If (FileName <> ".") And (FileName <> "..") And _ ((GetFileAttributes(path & FileName) And _ FILE_ATTRIBUTE_DIRECTORY) <> FILE_ATTRIBUTE_DIRECTORY) Then FindFilesAPI = FindFilesAPI + (WFD.nFileSizeHigh * _ MAXDWORD) + WFD.nFileSizeLow FileCount = FileCount + 1 ' To list files w/o dates, uncomment the next line ' and remove or Comment the lines down to End If 'List1.AddItem path & FileName ' Include Creation date... FileTimeToLocalFileTime WFD.ftCreationTime, FT FileTimeToSystemTime FT, ST DateCStr = ST.wMonth & "/" & ST.wDay & "/" & ST.wYear & _ " " & ST.wHour & ":" & ST.wMinute & ":" & ST.wSecond ' and Last Modified Date FileTimeToLocalFileTime WFD.ftLastWriteTime, FT FileTimeToSystemTime FT, ST DateMStr = ST.wMonth & "/" & ST.wDay & "/" & ST.wYear & _ " " & ST.wHour & ":" & ST.wMinute & ":" & ST.wSecond ListBox1.AddItem path & FileName & vbTab & _ Format(DateCStr, "mm/dd/yyyy hh:nn:ss") _ & vbTab & Format(DateMStr, "mm/dd/yyyy hh:nn:ss") End If Cont = FindNextFile(hSearch, WFD) ' Get next file Wend Cont = FindClose(hSearch) End If ' If there are sub-directories... If nDir > 0 Then ' Recursively walk into them... For i = 0 To nDir - 1 FindFilesAPI = FindFilesAPI + FindFilesAPI(path & dirNames(i) _ & "\", SearchStr, FileCount, DirCount) Next i End If End Function Private Sub CommandButton1_Click() Dim SearchPath As String, FindStr As String Dim FileSize As Long Dim NumFiles As Integer, NumDirs As Integer ListBox1.Clear SearchPath = TextBox1.Text FindStr = TextBox2.Text FileSize = FindFilesAPI(SearchPath, FindStr, NumFiles, NumDirs) TextBox3.Text = NumFiles & " Files found in " & NumDirs + 1 & _ " Directories" TextBox4.Text = "Size of files found under " & SearchPath & " = " & _ Format(FileSize, "#,###,###,##0") & " Bytes" End Sub
步骤4 测试运行,如下图所示。

方法2:使用内置的VBA函数
步骤1 在上例所示的界面中添加2个文本框(TextBox5用于报告搜索到多少个文件,TextBox6用于报告搜索到的文件总的大小),1个列表框(ListBox2用于列出搜索到的文件)。
步骤2 在用户窗体模块中添加下列代码:
Function FindFiles(path As String, SearchStr As String, _ FileCount As Integer, DirCount As Integer) Dim FileName As String ' Walking filename variable. Dim DirName As String ' SubDirectory Name. Dim dirNames() As String ' Buffer for directory name entries. Dim nDir As Integer ' Number of directories in this path. Dim i As Integer ' For-loop counter. On Error GoTo sysFileERR If Right(path, 1) <> "\" Then path = path & "\" ' Search for subdirectories. nDir = 0 ReDim dirNames(nDir) DirName = Dir(path, vbDirectory Or vbHidden Or vbArchive Or vbReadOnly _ Or vbSystem) ' Even if hidden, and so on. Do While Len(DirName) > 0 ' Ignore the current and encompassing directories. If (DirName <> ".") And (DirName <> "..") Then ' Check for directory with bitwise comparison. If GetAttr(path & DirName) And vbDirectory Then dirNames(nDir) = DirName DirCount = DirCount + 1 nDir = nDir + 1 ReDim Preserve dirNames(nDir) 'List2.AddItem path & DirName ' Uncomment to list End If ' directories. sysFileERRCont: End If DirName = Dir() ' Get next subdirectory. Loop ' Search through this directory and sum file sizes. FileName = Dir(path & SearchStr, vbNormal Or vbHidden Or vbSystem _ Or vbReadOnly Or vbArchive) While Len(FileName) <> 0 FindFiles = FindFiles + FileLen(path & FileName) FileCount = FileCount + 1 ' Load List box ListBox2.AddItem path & FileName & vbTab & _ FileDateTime(path & FileName) ' Include Modified Date FileName = Dir() ' Get next file. Wend ' If there are sub-directories.. If nDir > 0 Then ' Recursively walk into them For i = 0 To nDir - 1 FindFiles = FindFiles + FindFiles(path & dirNames(i) & "\", _ SearchStr, FileCount, DirCount) Next i End If AbortFunction: Exit Function sysFileERR: If Right(DirName, 4) = ".sys" Then Resume sysFileERRCont ' Known issue with pagefile.sys Else MsgBox "Error: " & Err.Number & " - " & Err.Description, , _ "Unexpected Error" Resume AbortFunction End If End Function Private Sub CommandButton2_Click() Dim SearchPath As String, FindStr As String Dim FileSize As Long Dim NumFiles As Integer, NumDirs As Integer ListBox2.Clear SearchPath = TextBox1.Text FindStr = TextBox2.Text FileSize = FindFiles(SearchPath, FindStr, NumFiles, NumDirs) TextBox5.Text = NumFiles & " Files found in " & NumDirs + 1 & _ " Directories" TextBox6.Text = "Size of files found under " & SearchPath & " = " & _ Format(FileSize, "#,###,###,##0") & " Bytes" End Sub Private Sub userForm_Initialize() CommandButton1.Caption = "使用API代码" CommandButton2.Caption = "使用VBA代码" ' start with some reasonable defaults TextBox1.Text = "C:\Documents and Settings\m\My Documents" TextBox2.Text = "*.*" End Sub
示例下载:
方法3:使用VBA文件系统对象
此方法可以参考前面的一系列文章。
注:本文整理自Microsoft知识库,将部分VB代码转换为VBA代码,并给出了详细的示例文档。





