how to find a file in a directory tree using the File Scripting Object

problem:

You are faced with the problem of finding a particular file in an extensive directory tree. You could do this by moving to each folder in turn with ChDir, then using the VB Dir function to check if the file exists, but there is a more flexible, object-oriented way: use the File Scripting Object (FSO).

solution:

1) Add a reference to the Windows Scripting Host to your project (Project | References, look for the Microsoft Scripting Runtime. The file name is scrrun.dll).

2) Create a module-level File Scripting Object in a form or code module:

Private fso as Scripting.FileSystemObject

And in code create the new object:

Set fso = New Scripting.FileSystemObject

3) You can now use the functions in the FSO to find the file. For example, suppose you want to look for a file ‘afile.txt’ which you think is somewhere in the \windows folder, which on your system might be ‘c:\windows’. The first thing to do is to get a Folder object for this folder:

Dim fsoFolder as Scripting.Folder
Set fsoFolder = fso.GetFolder(“c:\windows”)

The Folder object contains a Files collection, which is a collection of all files in the folder. So, all you need to do is check the name of each file in the Files collection. For this you need a File object, as the Files collection is a collection of File objects:

Dim fsoFile as Scripting.File

Then iterate through each file in the collection, checking for our file (‘afile.txt’):

For Each fsoFile in fsoFolder.Files
If fsoFile.Name = “afile.txt” Then
‘ found our file – do what we want with it
‘ e.g. open it, delete it, etc.
End If
Next

4) Unfortunately, all we’ve done is check the top-level folder, c:\windows. What about the myriad tree of folders beneath it? In the same way that the Folder object contains a Files collection, it also has a Folders collection which is a collection of Folder objects each of which is a sub-folder of the folder referenced by the initial Folder object (think about it!). This makes it easy to use recursion to search the entire tree.

We can now divide the code into three functions. We need two module-level variables:

Private m_sFoundFilePath As String ' holds the path to the file if it is found
Private m_bFound As Boolean ' set to True if the file is found

(Assumes we already have a File Scripting Object, named fso.) The functions we need are:

Public Function FindFile(sStartFolder As String, sFName As String) As String
' this is where we start. The parameters are:
' sStartFolder = the initial folder where the search will start (c:\windows in this example)
' sFName = the file to search for (e.g. ‘afile.txt’ in this example)

' create a folder object
Dim fsoFolder As Scripting.Folder

sFName = UCase(sFName)
m_sFoundFilePath = ""

' check that the start folder exists
If fso.FolderExists(sStartFolder) = True Then
' get a folder object for the top-level folder
Set fsoFolder = fso.GetFolder(sStartFolder)
' now check the start folder and each sub-folder in the start folder
CheckFolder fsoFolder, sFName
' return the path of the file, or a null string if it could not be found
FindFile = m_sFoundFilePath
Else
' if the start folder doesn't exist, raise path not found error
' which the user can trap
Err.Raise 76
End If

End Function

Here’s the routine to check each folder and each of that folder’s sub-folders:

Private Sub CheckFolder(fsoFolder As Scripting.Folder, sFName As String)
' this routine searches all folders and sub-folders recursively, parameters are:
' fsoFolder = a scripting folder object
' sFName = the file we are searching for

' create objects for a Files and a Folders collection, plus another Folder object
Dim colFiles As Scripting.Files
Dim colFolders As Scripting.Folders
Dim fsoNextFolder As Scripting.Folder

' get the files collection in this folder and then see if we can find the file we want
Set colFiles = fsoFolder.Files
CheckFiles colFiles, sFName

' if we didn't find it, check the folder’s subfolders
If m_bFound = False Then
' get the collection of all subfolders in this folder
Set colFolders = fsoFolder.SubFolders
' recursively check each sub folder and all its subfolders
For Each fsoNextFolder In colFolders
CheckFolder fsoNextFolder, sFName
' exit if we found the file
If m_bFound = True Then Exit For
Next fsoNextFolder
End If

End Sub

Finally, here’s the straightforward check of each file:

Private Sub CheckFiles(colFiles As Scripting.Files, sFName As String)
' this routine checks each file in a folder to see if it matches the one we're looking for
' parameters:
' colFiles = a Files collection of a Folder object
' sFName = the file we are searching for

' create a file object
Dim fsoFile As Scripting.File

' check the name of each file, and see if we have a match
For Each fsoFile In colFiles
If UCase(fsoFile.Name) = sFName Then
' we found the file, so set the module-level variable to give the file's path 
' and set the flag so we don't search any more folders
m_sFoundFilePath = fsoFile.Path
m_bFound = True
Exit For
End If
Next fsoFile

End Sub

When the function FindFile returns, it returns the path of the file if it was found, or a null string if it wasn’t. The easiest way to use this technique is wrap it into a class module. You can download the complete class together with a very simple example program in VB to demonstrate it.

Of course, the routine as shown could stand some improvement. For example, it only continues until it finds a matching file – what if there are several files with the same name scattered around a directory tree? And it could do with handling wildcards, as well. But that’s up to you to implement!

Download Download FSO Find File class (3.3K)