Difference between revisions of "Searching directories recursively"

From HashVB
Jump to: navigation, search
m (Added VB6 header)
m (Tidied up the code sample)
Line 4: Line 4:
 
It involves the use of the file finding APIs, the declarations for which are as follows:
 
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 FindFirstFile Lib "kernel32" Alias "FindFirstFileA" _
    Private Declare Function FindNextFile Lib "kernel32" Alias "FindNextFileA" (ByVal hFindFile As Long, lpFindFileData As WIN32_FIND_DATA) As Long
+
  (ByVal lpFileName As String, lpFindFileData As WIN32_FIND_DATA) As Long
    Private Declare Function GetFileAttributes Lib "kernel32" Alias "GetFileAttributesA" (ByVal lpFileName As String) As Long
+
Private Declare Function FindNextFile Lib "kernel32" Alias "FindNextFileA" _
    Private Declare Function FindClose Lib "kernel32" (ByVal hFindFile As Long) As Long
+
  (ByVal hFindFile As Long, lpFindFileData As WIN32_FIND_DATA) As Long
   
+
Private Declare Function GetFileAttributes Lib "kernel32" Alias "GetFileAttributesA" _
    Const MAX_PATH = 260
+
  (ByVal lpFileName As String) As Long
   
+
Private Declare Function FindClose Lib "kernel32" (ByVal hFindFile As Long) As Long
    Const INVALID_HANDLE_VALUE = -1
+
    Const FILE_ATTRIBUTE_ARCHIVE = &H20
+
Const MAX_PATH = 260
    Const FILE_ATTRIBUTE_DIRECTORY = &H10
+
    Const FILE_ATTRIBUTE_HIDDEN = &H2
+
Const INVALID_HANDLE_VALUE = -1
    Const FILE_ATTRIBUTE_NORMAL = &H80
+
Const FILE_ATTRIBUTE_ARCHIVE = &H20
    Const FILE_ATTRIBUTE_READONLY = &H1
+
Const FILE_ATTRIBUTE_DIRECTORY = &H10
    Const FILE_ATTRIBUTE_SYSTEM = &H4
+
Const FILE_ATTRIBUTE_HIDDEN = &H2
    Const FILE_ATTRIBUTE_TEMPORARY = &H100
+
Const FILE_ATTRIBUTE_NORMAL = &H80
   
+
Const FILE_ATTRIBUTE_READONLY = &H1
    Const MAXDWORD As Long = &HFFFFFFFF
+
Const FILE_ATTRIBUTE_SYSTEM = &H4
   
+
Const FILE_ATTRIBUTE_TEMPORARY = &H100
    Private Type FILETIME
+
        dwLowDateTime As Long
+
Const MAXDWORD As Long = &HFFFFFFFF
        dwHighDateTime As Long
+
    End Type
+
Private Type FILETIME
   
+
  dwLowDateTime As Long
    Private Type WIN32_FIND_DATA
+
  dwHighDateTime As Long
        dwFileAttributes As Long
+
End Type
        ftCreationTime As FILETIME
+
        ftLastAccessTime As FILETIME
+
Private Type WIN32_FIND_DATA
        ftLastWriteTime As FILETIME
+
  dwFileAttributes As Long
        nFileSizeHigh As Long
+
  ftCreationTime As FILETIME
        nFileSizeLow As Long
+
  ftLastAccessTime As FILETIME
        dwReserved0 As Long
+
  ftLastWriteTime As FILETIME
        dwReserved1 As Long
+
  nFileSizeHigh As Long
        cFileName As String * MAX_PATH
+
  nFileSizeLow As Long
        cAlternate As String * 14
+
  dwReserved0 As Long
    End Type
+
  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.
 
NOTE: I have also included all the other necessary declarations for using the code below.
Line 44: 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, ByVal DestDir As String) As Double
+
Public Function RecurseCopyDirs(ByVal StartDir As String, ByVal DestDir As String) As Double
        Dim s As String
+
Dim s As String
        Dim hSearch As Long
+
Dim hSearch As Long
        Dim WFD As WIN32_FIND_DATA
+
Dim WFD As WIN32_FIND_DATA
        Dim Cont As Integer
+
Dim Cont As Integer
        Dim DirSize As Double
+
Dim DirSize As Double
       
+
        If Right$(StartDir, 1) <> "\" Then StartDir = StartDir & "\"
+
  If Right$(StartDir, 1) <> "\" Then StartDir = StartDir & "\"
       
+
 
        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)
+
      s = StripNulls(WFD.cFileName)
               
+
     
                '-- Ignore the current and encompassing directories.
+
      'Ignore the current and encompassing directories.
                If (s <> ".") And (s <> "..") Then
+
      If (s <> ".") And (s <> "..") 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 & s) And FILE_ATTRIBUTE_DIRECTORY Then
                        Debug.Print "DIR", StartDir & s
+
          Debug.Print "DIR", StartDir & s
                        DirSize = DirSize + RecurseCopyDirs(StartDir & s)
+
          DirSize = DirSize + RecurseCopyDirs(StartDir & s)
                    Else
+
        Else
                        Debug.Print "FILE", StartDir & s
+
          Debug.Print "FILE", StartDir & s
                        DirSize = DirSize + CDbl(CStr(WFD.nFileSizeHigh)) * (MAXDWORD + 1) + WFD.nFileSizeLow
+
          DirSize = DirSize + CDbl(CStr(WFD.nFileSizeHigh)) * (MAXDWORD + 1) + WFD.nFileSizeLow
                    End If
+
        End If
                End If
+
      End If
                Cont = FindNextFile(hSearch, WFD)
+
      Cont = FindNextFile(hSearch, WFD)
            Loop
+
    Loop
            Cont = FindClose(hSearch)
+
    Cont = FindClose(hSearch)
        End If
+
  End If
       
+
 
        RecurseCopyDirs = DirSize
+
  RecurseCopyDirs = DirSize
    End Function
+
End Function
   
+
    Function StripNulls(OriginalStr As String) As String
+
Function StripNulls(OriginalStr As String) As String
        If (InStr(OriginalStr, Chr(0)) > 0) Then
+
  If (InStr(OriginalStr, Chr(0)) > 0) Then
            OriginalStr = Left(OriginalStr, InStr(OriginalStr, Chr(0)) - 1)
+
    OriginalStr = Left(OriginalStr, InStr(OriginalStr, Chr(0)) - 1)
        End If
+
  End If
        StripNulls = OriginalStr
+
  StripNulls = OriginalStr
    End Function
+
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.
 
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.
 
Enjoy.

Revision as of 22:16, 15 December 2005

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 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.