|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Prerequisites |
None. |
|
VBnet
already contains several pages that show how to use the FindFirstFile and
FindNextFile APIs to rapidly search for files or folders. Yet
several programmers have asked for pages that provide just the most
minimal code to retrieve either file or folder info, across single or
multiple drives. This series of four pages address these requests. Certainly the easiest way to pass multiple search parameters to search routines is via a customized User-Defined Type, and this demo, like the other FindFirstFile demos, uses a UDT to allow for extending the capabilities of a routine by simply adding a new member to the UDT. This page shows the minimalist code for searching a singe drive for all folders under the specified start path. Searching for folders requires just search routine, with a couple of support methods to parse the returned strings once it has been determined that a folder has been located. The routine is extremely fast, as the illustration shows, and for a non-recursive search is just a bit faster than a corresponding Dir() method. However, the routine really shines in a recursive search as it is considerably faster than a recursive Dir() method. Compared to the FindFirstFile methods , the FileSystemObject is, well, no comparison. Create your own demo to see the huge performance hit that the collection in the FSO imparts on your search or see the comparison demo in Related above. The default mode coded is to search only the specified folder. When the "Recurse" button is checked, the specified folder, and all subfolders under it, are searched. When a drive alone is specified as the source path, the recursion searches all folders on the drive. Notes:
|
BAS Module Code |
None. |
|
Form Code |
Create a new project with a form containing four text boxes (Text1, Text2, Text3, Text4), a check boxes (Check1), a list box (List1) and a command button (Command1). Label as desired and add the following 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 MAXDWORD As Long = &HFFFFFFFF Private Const MAX_PATH As Long = 260 Private Const INVALID_HANDLE_VALUE = -1 Private Const FILE_ATTRIBUTE_DIRECTORY = &H10 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 sFileRoot As String sFileNameExt As String sResult As String sMatches As String Count As Long 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 Sub Command1_Click() Dim FP As FILE_PARAMS 'holds search parameters Dim tstart As Single 'timer var for this routine only Dim tend As Single 'timer var for this routine only 'clear results textbox and list Text3.Text = "" 'set up search params With FP .sFileRoot = Text1.Text 'start path .sFileNameExt = Text2.Text 'file type of interest .bRecurse = Check1.Value = 1 '1 = do recursive search End With 'setting the list visibility to false 'increases clear and load time List1.Visible = False List1.Clear 'get start time, folders, and finish time tstart = GetTickCount() Call SearchForFolders(FP) tend = GetTickCount() List1.Visible = True 'show the results Text3.Text = Format$(FP.Count, "###,###,###,##0") & _ " found (" & _ FP.sFileNameExt & ")" Text4.Text = FormatNumber((tend - tstart) / 1000, 2) & " seconds" End Sub Private Sub SearchForFolders(FP As FILE_PARAMS) Dim WFD As WIN32_FIND_DATA Dim hFile As Long Dim sRoot As String Dim spath As String Dim sTmp As String sRoot = QualifyPath(FP.sFileRoot) spath = sRoot & FP.sFileNameExt 'obtain handle to the first match hFile = FindFirstFile(spath, WFD) 'if valid ... If hFile <> INVALID_HANDLE_VALUE Then Do 'Only folders are wanted, so discard files 'or parent/root DOS folders. If (WFD.dwFileAttributes And FILE_ATTRIBUTE_DIRECTORY) And _ Asc(WFD.cFileName) <> vbDot Then 'must be a folder, so remove trailing nulls sTmp = TrimNull(WFD.cFileName) 'This is where you add code to store 'or display the returned file listing. ' 'if you want the folder name only, save 'sTmp'. 'if you want the full path, save 'sRoot & sTmp' FP.Count = FP.Count + 1 List1.AddItem sRoot & sTmp 'if a recursive search was selected, call 'this method again with a modified root If FP.bRecurse Then FP.sFileRoot = sRoot & sTmp Call SearchForFolders(FP) End If End If Loop While FindNextFile(hFile, WFD) 'close the handle hFile = FindClose(hFile) End If End Sub Private Function TrimNull(startstr As String) As String 'returns the string up to the first 'null, if present, or the passed string Dim pos As Integer pos = InStr(startstr, Chr$(0)) If pos Then TrimNull = Left$(startstr, pos - 1) Exit Function End If TrimNull = startstr End Function Private Function QualifyPath(spath As String) As String 'assures that a passed path ends in a slash If Right$(spath, 1) <> "\" Then QualifyPath = spath & "\" Else QualifyPath = spath End If 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 read (if exceeding the size of a Long), by declaring the appropriate variables as Currency instead. 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. |