October 1999

Recursively Search Subfolders with the New FileSystemObject

Until recently, most file search techniques involved using the Dir() function or several intricate API calls. In addition, the Dir() function made it next to impossible to search through subfolders within a directory. When you did find the appropriate file, Dir() returned an unwieldy path string. As a result, you've no doubt developed all kinds of procedures to parse certain sections from this path, such as the filename, parent folder, and root folder. And forget about determining other file attributes such as the file's size and type. If you've ever been frustrated with this limited function, then you'll be happy to know that Microsoft has developed a much-needed improvement called the FileSystemObject. With this new object library, you can manipulate a computer's directory structure in true OOP fashion.

In this article, we'll show you a few of the FileSystemObject's exciting features, methods, and properties. In addition, we'll show you how to recursively search through subfolders and create a list of files over a specific size using the utility shown in Figure A.

Figure A: The FileSystemObject not only lets you search through subfolders, but it also lets you easily determine file attributes, such as Name, Size, and Type.

How to get the scrrun.dll

This handy type library is contained within the Scripting Runtime Library (scrrun.dll), which is installed with the Windows Scripting Host, Windows NT Option Pack, Internet Information Server 3.0, Scripting 3.1 upgrade, Visual Studio 98, or Visual Basic 6.0. If you don't have any of these programs, you can download it from our ftp site. (If you do use our download, copy the DLL file directly into the Windows/System directory.) Microsoft originally created the FileSystemObject library as a lightweight, quick way to manipulate a computer's file structure via the Internet. However, you can use it just as well in regular Visual Basic applications. While it's not supported for VB 5.0, it works with this version just fine. In fact, we developed this article's example in 5.0.

The FileSystemObject object model

The FileSystemObject is the top-level object within the file structure hierarchy, and you create an instance of it just like you would with any other OLE object:

Set fso = New Scripting.FileSystemObject

Within it, the structure cascades as you'd expect, from Drives to Folders (including the convenient Subfolders--more on this later) to Files. To create a Drive, Folder, or File object variable from a path, you use the Get family of methods: GetDrive, GetFolder, and GetFile. For example, to create a File object based on C:\text.txt, you'd use something like

Set fso = New Scripting.FileSystemObject
Set sysFile = fso.GetFile("C:\text.txt")
Now that we've covered the top-level object, let's delve a little deeper down the hierarchy.

The Drive object

The Drive object lets you determine its TotalSize, as well as the AvailableSpace and FreeSpace values. The DriveType property indicates, among others, if the drive is removable, fixed, networked, or a CD-ROM. The IsReady property determines if a specified drive, such as the floppy drive, is available. Finally, the DriveLetter property specifies the letter assigned to each drive.

The Folder object

Folders come next in the hierarchy. With the FolderSystemObject library, you can create, delete, move, and copy folders, as well as find out if a specific folder exists. The FolderExists method provides this feature. In addition to the standard Files collection, each Folder also contains a SubFolders collection, which, as you can guess, contains all the child folders within the parent. In our example, we'll create a recursive procedure that searches for files within a specified directory and all of its subfolders. The FileSystemObject library makes it easy to do so.

The File object

At the bottom of the object model lies the File object. In addition to standard file manipulation, such as copying, deleting, moving, and creating, each File object has a Size, Name, Path, and Type property. These attributes let you determine information about files that the Dir() function simply can't provide. The first three properties are fairly self-explanatory. The Type property returns the same string value that appears in the Type column of Windows Explorer. For example, Windows lists files with a .doc extension as Microsoft Word Document types. The Type property of a .doc file returns the same phrase. Now that we've exposed you to a few of this new type library's many features, let's see how you might use it in an application.

Build the FatFile example

For our utility, we'll use the FileSystemObject to list files larger than the indicated search size. We'll use the standard DriveListbox and DirListbox controls to allow the initial directory selection, and then set up a recursive procedure to loop through all the subsequent folders within the chosen directory. When the procedure finds files larger than the indicated size, we'll place their name, size, and type in the ListView control. We'll use VB 5.0 as our development environment, but you can easily use VB 6.0, or even modify our technique for use in any of the Microsoft Office applications, for that matter.

To begin, create a new standard project in the IDE. Next, set a reference to the Scripting Runtime Library. To do so, select Project | References from the menu bar. Choose Microsoft Scripting Runtime, and then click OK. Now, select Project | Add Form to add a standard form. Figure B shows our form's design. Use it as a guide to place your own controls. Table A lists each object's more relevant settings.

Figure B: Our procedure fills the ListView control with file information gathered from the directory you specify.

Table A: The FatFile form's object settings
Object

Property

Value

Form Name frmFatFile
  Caption FatFile Search
  Height 5460
  Width 5760
DriveListbox Name drvDriveList
  Width 2325
DirListbox Name dirFolderList
  Height 1665
  Width 2325
Textbox Name txtFileSize
  Width 1665
ListView Name lstvwFatFiles
  Height 2475
  Width 5370
CommandButton Name cmdSearch
  Caption Search

When you add the ListView control, right-click on it and select Properties from the shortcut menu. In the Property Pages dialog box, choose 3 - lvwReport as the View. Deselect HideSelection and LabelWrap, if necessary, and choose FullRowSelect.

Now, click on the Column Headers tab. Click Insert Column and enter File in the Text field. Enter 2160 as the Width. Next, create two more Column Headers, Size (KB) and Type. Give the Size (KB) column a 1000 pixel width, and the Type header 2160. Click OK after you've finished to return to the form's design. At this point, all we need to do is attach the code that uses the FileSystemObject object.

FatFile's search procedure and misc. code

To attach the form's code, right-click anywhere on the form and select View Code from the shortcut menu. Listing A shows the miscellaneous code for our example. Enter it directly into the code window. As you can see, the code initializes and sets a FileSystemObject variable for use as long as the form is running. In addition, it synchronizes the DriveListbox with the DirListbox. The cmdSearch button's Click event creates a Folder object based on the current directory selection, clears the items in the ListView control, and then calls the AddItems procedure, which does most of the actual work in our example. Listing B shows this procedure. Add it next.

Listing A: Miscellaneous code for the frmFatFile form

Option Explicit
Dim scrFileSys As Scripting.FileSystemObject
Private Sub drvDriveList_Change()
dirFolderList.Path = drvDriveList
End Sub

Private Sub Form_Load()
Set scrFileSys = New Scripting.FileSystemObject
dirFolderList.Path = drvDriveList.Drive & "\"
End Sub

Private Sub Form_Unload(Cancel As Integer)
Set scrFileSys = Nothing
End Sub

Private Sub cmdSearch_Click()
Dim fldStart As Scripting.Folder
Set fldStart = scrFileSys.GetFolder(dirFolderList.Path)
lstvwFatFiles.ListItems.Clear
AddFiles fldStart
End Sub

Listing B: The AddFile sub procedure

Private Sub AddFiles(fldSearch As Scripting.Folder)
Dim fld As Scripting.Folder
Dim fyl As Scripting.File
Dim sngFileSize As Single
Dim lngSize As Long
Dim itm As ListItem

If fldSearch.SubFolders.Count Then
	For Each fld In fldSearch.SubFolders
		AddFiles fld
	Next fld
End If
sngFileSize = txtFileSize * 1000
For Each fyl In fldSearch.Files
	With fyl
		If .Size >= sngFileSize Then
			Set itm = lstvwFatFiles.ListItems.Add _
				(Text:=.Name)
			lngSize = .Size / 1000
			With itm
				.SubItems(1) = Format(lngSize, "#,###")
				.SubItems(2) = fyl.Type
			End With
		End If
	End With
Next fyl

Set itm = Nothing
Set fld = Nothing
End Sub

Searching for system bloat

Press [Ctrl][F5] to run the utility. Select any directory on your system and enter a number in the text box; then, click Search. When you do, the utility calls the AddFiles procedure and passes the starting folder object. The AddFiles procedure first checks to see if the folder contains subfolders. If it does, it makes a call to the AddFiles procedure for each successive subfolder until it reaches the last folder in the branch. Next, the procedure searches through the files in each folder. If the file is greater than or equal to the file size in txtFile, then the procedure adds its name, size, and type to the ListView control. Because, we created a recursive procedure, VB starts at the bottom folder and works its way back up to the starting folder, looping through the relevant file collections as it goes.

Conclusion

The FileSystemObject provides a powerful and versatile tool for manipulating a system's file structure, and in this article we've only scratched the surface. However, we've shown you how this new type library can improve and simplify file manipulations and subfolder searches using a recursive subroutine.

Copyright © 1999, ZD Inc. All rights reserved. ZD Journals and the ZD Journals logo are trademarks of ZD Inc. Reproduction in whole or in part in any form or medium without express written permission of ZD Inc. is prohibited. All other product names and logos are trademarks or registered trademarks of their respective owners.