This short article describes a technique (with source code provided) that provides a variant to the many recursive solutions for retrieving and searching directory structures that are now available to developers over the Internet on technical sites.
It is by far not the most efficient solution and undoubtedly developers who download the code and tinker with it will find more efficient solutions. However, it does provide an in-depth technique that will search all directories within a root directory structure for a specified file.
This scenario can be most beneficial in applications that require the ability to test for example the existence of installed prerequisites prior to the installation of a given application. In my own project that I am currently developing for distribution, I require to know if the SQL Server LocalDB database engine has been previously installed by the user by testing for its API utility, SqlLocalDB.exe, which is installed along with the engine itself (One could test for another file but in my case this file appeared to be the most logical choice).
General Module Notes
The code is contained in a single module within a console application, which can be easily converted into a class. My apologies for using the VB.NET language but it is my preferred language in development unless I am working on a military simulation for which I then use C#. Nonetheless, any competent conversion utility should be able to easily c onvert the code to C#.
The module is divided into several sections, beginning with the top-level declarations as follows…
#Region "Module Level Declarations" Private msModule As String= "SqlLocalDB.exe" Private msInitialDirectory As String = "Program Files\Microsoft SQL Server\"PrivatemsInitialDirectory" Private moDirectoryArrayList As New ArrayList() Private moDirectorySavedArrayList As New ArrayList() #End Region
The top two or three declarations were implemented merely for simplicity of testing. One can easily modify the code to accept such data as passed arguments. However, as you will see the two array-lists are required by the code as is.
Most would agree that array-lists are not the most efficient type of collection to use and in fact, for the purposes in this module simple arrays could be used just as easily. However, I like using array-lists since they have all of the features I like to make coding easier, especially as you will see the ability to easily remove an item.
The processing code itself is divided into the following methods…
- Main Method
Master call to all of the processing. Would be made into a public method in a class.
The primary sub-master method that provides the logical drives to search and the call to search the given directory structure.
Will return all of the logical drives attached to a workstation
Sets up the for-loop that processes all of the logical drives for a defined search path and calls the Find_Module() to initiate the processing of a search in all the found sub-directories.
Gets the first level of sub-directories to the initial search path (which can be simply a drive designation or a directory path lower in the drive’s hierarchy; however, the higher in the hierarchy the initial search path is, the longer the search will take). This method also retrieves all of the sub-directories through the call to the recursive method,Find_AllSubDirectories(lsDirectory).
The recursive method that acquires all sub-directories to a given sub-directory
Developing this code was more or less a trail and error process as I was not aware of all the possibilities that such a search could entail.
For one thing, if you apply an action to a directory or a file to which your application has no access, an “access denied” error will be yielded. This is why the “unauthorized” exception error is tested for in the Find_AllSubDirectories() method and general exceptions are caught in other areas of the code.
Another cause for an exception is access to a logical drive that may not be active. For example, the retrieval of logical drives may yield your DVD drive, which may not have a DVD inserted into it. A “drive not ready” exception will occur under such circumstances but the included error trapping will avoid such an issue.
Most of the solutions I found on the Internet for such a search would only yield their search depths to a single hierarchical path in any given directory structure, which I found not only limiting but rather odd given that such solutions would be quite limited in their application. As a result, the code provided will search every sub-directory hierarchy found for any initial search path provided.
It should also be noted that instead of simply going through every retrieved directory and testing for the particular file being searched for, I first add each of the legitimately found directory paths into an array-list. This may seem inefficient at first, and to a certain extent it is. However, instead of making the code slightly more complicated by weaving “unauthorized” exceptions into the testing of the searched for file, I am able to simply delete the unauthorized directory from the array-list and continue on with the next found directory.
On a final note, it should be remembered that the lower in the hierarchy an initial search path is, the faster a search will go. If no initial search path is provided (then a blank must be passed to the code -> “”), the code will then default to a drive root directory as its beginning point. On a medium-to-heavy populated drive, such a search may take between 30 and 60 seconds.
The code requires for processing an initial search path and the name of the file to be found. Currently the verification of the searched-for file is case sensitive.
Any developer could easily find some fault with this code-base but it does work and rather nicely without too much complexity involved.
I would be very interested to hear any comments by anyone who downloads the code from the following link…