|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Prerequisites |
None. |
|
OK .. so the page title is starting to become a tad unwieldy. But it does accurately represent what this page shows - how to perform a recursive search for files across a single drive, while specifying a single or multiple file mask, and whether the search routine should include or exclude the masked files. When exclude is selected with the demo's *.doc;*.xls;*.ppt mask, the routine returns all files that are not word docs, excel spreadsheets, or PowerPoint presentations. And adding this functionality is simple. As the FindFirstFile: Recursive File Search for Single or Multiple File Types (minimal code) demo showed, PathMatchSpec API returns 1 if the passed filename matched a passed file spec, or 0 if it didn't. By adding a new Type member to the FILE_PARAMS type (bFindOrExclude), we can have the MatchSpec function check its return value from PathMatchSpec against the value we want to know about. If we selected "Only find listed types", we set bFindOrExclude to 1; if "Find all but listed types" is selected, we set bFindOrExclude = 0. In MatchSpec, the function returns True if the return value of the API call is the value we want, or false otherwise, thus listing the files that match the file specs, or the files that do not. Notes:
|
BAS Module Code |
None. |
|
Form Code |
Create a new project with a form containing five text boxes (Text1, Text2, Text3, Text4, Text5), a check box (Check1), a list box (List1), two option buttons in an option array (Option1(0), Option1(1), and a command button (Command1). Label as desired and add the following code. The bolded text indicates the differences between this code and that from FindFirstFile: Recursive File Search for Single or Multiple File Types (minimal code): |
|
Option Explicit '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved. ' Some pages may also contain other copyrights by the author. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Distribution: You can freely use this code in your own ' applications, but you may not reproduce ' or publish this code on any web site, ' online service, or distribute as source ' on any media without express permission. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Private Const vbDot = 46 Private Const MAX_PATH As Long = 260 Private Const INVALID_HANDLE_VALUE = -1 Private Const vbBackslash = "\" Private Const ALL_FILES = "*.*" Private Type FILETIME dwLowDateTime As Long dwHighDateTime As Long End Type Private 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 Private Type FILE_PARAMS bRecurse As Boolean bFindOrExclude As Long '1=find matching, 0=exclude matching nCount As Long nSearched As Long sFileNameExt As String sFileRoot As String End Type Private Declare Function FindClose Lib "kernel32" _ (ByVal hFindFile As Long) As Long Private Declare Function FindFirstFile Lib "kernel32" _ Alias "FindFirstFileA" _ (ByVal lpFileName As String, _ lpFindFileData As WIN32_FIND_DATA) As Long Private Declare Function FindNextFile Lib "kernel32" _ Alias "FindNextFileA" _ (ByVal hFindFile As Long, _ lpFindFileData As WIN32_FIND_DATA) As Long Private Declare Function GetTickCount Lib "kernel32" () As Long Private Declare Function lstrlen Lib "kernel32" _ Alias "lstrlenW" (ByVal lpString As Long) As Long Private Declare Function PathMatchSpec Lib "shlwapi" _ Alias "PathMatchSpecW" _ (ByVal pszFileParam As Long, _ ByVal pszSpec As Long) As Long Private fp As FILE_PARAMS 'holds search parameters Private Sub Form_Load() Text1.Text = "c:\" Text2.Text = "*.doc; *.xls; *.ppt" Option1(0).Value = True Command1.Caption = "Begin Search" End Sub Private Sub Command1_Click() Dim tstart As Single 'timer var for this routine only Dim tend As Single 'timer var for this routine only Text3.Text = "" Text4.Text = "" Text5.Text = "" List1.Clear List1.Visible = False With fp .sFileRoot = QualifyPath(Text1.Text) 'start path .sFileNameExt = Text2.Text 'file type(s) of interest .bRecurse = Check1.Value = 1 'True = recursive search .nCount = 0 'results .nSearched = 0 'results .bFindOrExclude = IIf(Option1(0).Value = True, 1, 0) '0=include, 1=exclude End With tstart = GetTickCount() Call SearchForFiles(fp.sFileRoot) tend = GetTickCount() List1.Visible = True Text3.Text = Format$(fp.nSearched, "###,###,###,##0") Text4.Text = Format$(fp.nCount, "###,###,###,##0") Text5.Text = FormatNumber((tend - tstart) / 1000, 2) & " seconds" End Sub Private Sub SearchForFiles(sRoot As String) Dim WFD As WIN32_FIND_DATA Dim hFile As Long hFile = FindFirstFile(sRoot & ALL_FILES, WFD) If hFile <> INVALID_HANDLE_VALUE Then Do 'if a folder, and recurse specified, call 'method again If (WFD.dwFileAttributes And vbDirectory) Then If Asc(WFD.cFileName) <> vbDot Then If fp.bRecurse Then SearchForFiles sRoot & TrimNull(WFD.cFileName) & vbBackslash End If End If Else 'must be a file.. If MatchSpec(WFD.cFileName, fp.sFileNameExt) Then fp.nCount = fp.nCount + 1 List1.AddItem sRoot & TrimNull(WFD.cFileName) End If 'If MatchSpec End If 'If WFD.dwFileAttributes fp.nSearched = fp.nSearched + 1 Loop While FindNextFile(hFile, WFD) End If 'If hFile Call FindClose(hFile) End Sub Private Function QualifyPath(sPath As String) As String If Right$(sPath, 1) <> vbBackslash Then QualifyPath = sPath & vbBackslash Else QualifyPath = sPath End If End Function Private Function TrimNull(startstr As String) As String TrimNull = Left$(startstr, lstrlen(StrPtr(startstr))) End Function Private Function MatchSpec(sFile As String, sSpec As String) As Boolean MatchSpec = PathMatchSpec(StrPtr(sFile), StrPtr(sSpec)) = fp.bFindOrExclude End Function |
Comments |
Before running, assure that any hard-coded paths reflect accurate paths on your system.
It must also be noted that, since this example uses the listbox to return the results, on systems containing many files you may, eventually, hit the listbox item limit of 32k items under an non-NT-based system. While there is no practical or reliable way to extend the number of items a listbox can contains on a Win9x system (without resorting to an owner-drawn control), you can increase the number of files the method is capable storing (if exceeding the size of a Long), by declaring the appropriate variables as Currency instead of Long. Note: While it may be convenient to utilize VB's built-in constants in place of the FILE_ATTRIBUTE_* API values, care must be taken. There is a difference between related constant values that may cause unexpected performance at some point. For example, the constant 'vbNormal' is defined as having a value of 0, whereas the API FILE_ATTRIBUTE_NORMAL has a value of &H80 (decimal 128). |
|
|
|
|||||
|
|||||
|
|||||
Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved. |