|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Prerequisites |
None. |
|
Windows
does not expose an API that will return the total size of a folder, or the total
size of all specified file types (ie *.doc), so we revert
to the trusty FindFirstFile and FindNextFile APIs to retrieve this info for us.
This demo shows how to retrieve the directory size beginning at the root path,
and optionally recursing and including the size of subdirectories under that
path. By changing the hard-coded *.* you can restrict the returned value to a
specific file type. As used in the other search demos, a customized User-Defined Type is used as the mechanism to pass multiple search parameters to the search routines. This allows for extending the capabilities of a routine by simply adding a new member to the UDT and coding for it. The default mode is to search only within 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, without recursion the files in the root are returned, otherwise the recursion searches all folders on the drive. Note:
|
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 nFileCount As Long nFileSize As Currency '64 bit value 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 lstrlen Lib "kernel32" _ Alias "lstrlenW" (ByVal lpString As Long) As Long Private Declare Function GetTickCount Lib "kernel32" () As Long Private Sub Form_Load() Text1.Text = "c:\windows" Check1.Caption = "Recurse" Command1.Caption = "GetDirectorySize" 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 Dim fp As FILE_PARAMS Text2.Text = "" Text3.Text = "" Text4.Text = "" With fp .sFileRoot = QualifyPath(Text1.Text) 'start path .sFileNameExt = "*.*" 'files of interest .bRecurse = Check1.Value = 1 'True = recurse End With tstart = GetTickCount() Call GetDirectorySize(fp.sFileRoot, fp) tend = GetTickCount() Text2.Text = Format$(fp.nSearched, "###,###,###,##0") Text3.Text = Format$(fp.nFileSize, "###,###,###,##0") Text4.Text = FormatNumber((tend - tstart) / 1000, 2) & " seconds" End Sub Private Sub GetDirectorySize(sRoot As String, fp As FILE_PARAMS) Dim wfd As WIN32_FIND_DATA Dim hFile As Long hFile = FindFirstFile(sRoot & "*.*", wfd) If hFile <> INVALID_HANDLE_VALUE Then Do If Asc(wfd.cFileName) <> vbDot Then If (wfd.dwFileAttributes And vbDirectory) Then If fp.bRecurse Then GetDirectorySize sRoot & TrimNull(wfd.cFileName) & "\", fp End If 'If fp.bRecurse Else fp.nFileCount = fp.nFileCount + 1 fp.nFileSize = fp.nFileSize + _ ((wfd.nFileSizeHigh * _ (MAXDWORD + 1)) + _ wfd.nFileSizeLow) End If 'If WFD.dwFileAttributes End If 'If Asc(wfd.cFileName) fp.nSearched = fp.nSearched + 1 Loop While FindNextFile(hFile, wfd) End If 'If hFile Call FindClose(hFile) End Sub Private Function TrimNull(startstr As String) As String TrimNull = Left$(startstr, lstrlen(StrPtr(startstr))) End Function Private Function QualifyPath(sPath As String) As String If Right$(sPath, 1) <> "\" Then QualifyPath = sPath & "\" Else QualifyPath = sPath End If End Function |
Comments |
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. |