Difference between revisions of "Searching directories recursively"

From HashVB
Jump to: navigation, search
(Tidied up the sample code and corrected the function name)
 
Line 47: Line 47:
 
The code that will actually recurse through the directories goes like this:
 
The code that will actually recurse through the directories goes like this:
  
  Public Function RecurseCopyDirs(ByVal StartDir As String) As Double
+
  Public Function CountDirSize(ByVal StartDir As String) As Double
  Dim s As String
+
  Dim Filename As String
 
  Dim hSearch As Long
 
  Dim hSearch As Long
 
  Dim WFD As WIN32_FIND_DATA
 
  Dim WFD As WIN32_FIND_DATA
Line 54: Line 54:
 
  Dim DirSize As Double
 
  Dim DirSize As Double
 
   
 
   
 +
  'Add the final \
 
   If Right$(StartDir, 1) <> "\" Then StartDir = StartDir & "\"
 
   If Right$(StartDir, 1) <> "\" Then StartDir = StartDir & "\"
 
+
 
 +
  'Enumerate the directories
 
   hSearch = FindFirstFile(StartDir & "*", WFD)
 
   hSearch = FindFirstFile(StartDir & "*", WFD)
 
   If hSearch <> INVALID_HANDLE_VALUE Then
 
   If hSearch <> INVALID_HANDLE_VALUE Then
 
     Cont = True
 
     Cont = True
 
     Do While Cont
 
     Do While Cont
       s = StripNulls(WFD.cFileName)
+
       Filename = StripNulls(WFD.cFileName)
 
        
 
        
 
       'Ignore the current and encompassing directories.
 
       'Ignore the current and encompassing directories.
       If (s <> ".") And (s <> "..") Then
+
       If (Filename <> ".") And (Filename <> "..") Then
 
         'Check if it's a directory
 
         'Check if it's a directory
         If GetFileAttributes(StartDir & s) And FILE_ATTRIBUTE_DIRECTORY Then
+
         If GetFileAttributes(StartDir & Filename) And FILE_ATTRIBUTE_DIRECTORY Then
           Debug.Print "DIR", StartDir & s
+
           Debug.Print "DIR", StartDir & Filename
           DirSize = DirSize + RecurseCopyDirs(StartDir & s)
+
           DirSize = DirSize + CountDirSize(StartDir & Filename)
 
         Else
 
         Else
           Debug.Print "FILE", StartDir & s
+
           Debug.Print "FILE", StartDir & Filename
 
           DirSize = DirSize + CDbl(CStr(WFD.nFileSizeHigh)) * (MAXDWORD + 1) + WFD.nFileSizeLow
 
           DirSize = DirSize + CDbl(CStr(WFD.nFileSizeHigh)) * (MAXDWORD + 1) + WFD.nFileSizeLow
 
         End If
 
         End If
Line 78: Line 80:
 
   End If
 
   End If
 
    
 
    
   RecurseCopyDirs = DirSize
+
   CountDirSize = DirSize
 
  End Function
 
  End Function
 
   
 
   

Latest revision as of 13:53, 5 January 2007

float
 This article is based on Visual Basic 6. Find other Visual Basic 6 articles.

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 CountDirSize(ByVal StartDir As String) As Double
Dim Filename As String
Dim hSearch As Long
Dim WFD As WIN32_FIND_DATA
Dim Cont As Integer
Dim DirSize As Double

  'Add the final \
  If Right$(StartDir, 1) <> "\" Then StartDir = StartDir & "\"
  
  'Enumerate the directories
  hSearch = FindFirstFile(StartDir & "*", WFD)
  If hSearch <> INVALID_HANDLE_VALUE Then
    Cont = True
    Do While Cont
      Filename = StripNulls(WFD.cFileName)
      
      'Ignore the current and encompassing directories.
      If (Filename <> ".") And (Filename <> "..") Then
        'Check if it's a directory
        If GetFileAttributes(StartDir & Filename) And FILE_ATTRIBUTE_DIRECTORY Then
          Debug.Print "DIR", StartDir & Filename
          DirSize = DirSize + CountDirSize(StartDir & Filename)
        Else
          Debug.Print "FILE", StartDir & Filename
          DirSize = DirSize + CDbl(CStr(WFD.nFileSizeHigh)) * (MAXDWORD + 1) + WFD.nFileSizeLow
        End If
      End If
      Cont = FindNextFile(hSearch, WFD)
    Loop
    Cont = FindClose(hSearch)
  End If
  
  CountDirSize = 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.