Searching directories recursively

From HashVB
Revision as of 01:08, 20 October 2005 by Wakjah (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

This is a useful technique that allows you to search for files and build directory trees a lot faster than the intrinsic VB methods allow.

It involves the use of the file finding APIs, the declarations for which are as follows:

   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 GetFileAttributes Lib "kernel32" Alias "GetFileAttributesA" (ByVal lpFileName As String) As Long
   Private Declare Function FindClose Lib "kernel32" (ByVal hFindFile As Long) As Long
   
   Const MAX_PATH = 260
   
   Const INVALID_HANDLE_VALUE = -1
   Const FILE_ATTRIBUTE_ARCHIVE = &H20
   Const FILE_ATTRIBUTE_DIRECTORY = &H10
   Const FILE_ATTRIBUTE_HIDDEN = &H2
   Const FILE_ATTRIBUTE_NORMAL = &H80
   Const FILE_ATTRIBUTE_READONLY = &H1
   Const FILE_ATTRIBUTE_SYSTEM = &H4
   Const FILE_ATTRIBUTE_TEMPORARY = &H100
   
   Const MAXDWORD As Long = &HFFFFFFFF
   
   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

NOTE: I have also included all the other necessary declarations for using the code below.

The code that will actually recurse through the directories goes like this:

   Public Function RecurseCopyDirs(ByVal StartDir As String, ByVal DestDir As String) As Double
       Dim s As String
       Dim hSearch As Long
       Dim WFD As WIN32_FIND_DATA
       Dim Cont As Integer
       Dim DirSize As Double
       
       If Right$(StartDir, 1) <> "\" Then StartDir = StartDir & "\"
       
       hSearch = FindFirstFile(StartDir & "*", WFD)
       If hSearch <> INVALID_HANDLE_VALUE Then
           Cont = True
           Do While Cont
               s = StripNulls(WFD.cFileName)
               
               '-- Ignore the current and encompassing directories.
               If (s <> ".") And (s <> "..") Then
                   '-- Check if it's a directory
                   If GetFileAttributes(StartDir & s) And FILE_ATTRIBUTE_DIRECTORY Then
                       Debug.Print "DIR", StartDir & s
                       DirSize = DirSize + RecurseCopyDirs(StartDir & s)
                   Else
                       Debug.Print "FILE", StartDir & s
                       DirSize = DirSize + CDbl(CStr(WFD.nFileSizeHigh)) * (MAXDWORD + 1) + WFD.nFileSizeLow
                   End If
               End If
               Cont = FindNextFile(hSearch, WFD)
           Loop
           Cont = FindClose(hSearch)
       End If
       
       RecurseCopyDirs = DirSize
   End Function
   
   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

This will print all of the files, directories and subdirectories under the directory that you provide it with to the Immediate window, and, as an added bonus, returns the total size of the files in the directory tree.

Enjoy.