1

I have a situation where I have to find a path to the first file named my.exe starting from startingdirectory & \mydir\ and go deep as needed.
Actually, IO.Directory.GetFiles is suitable but I need it stop searching after the first file is found like it is possible with FindFirstFile from WinAPI.

VB.NET

Dim findedDirectories() As String = IO.Directory.GetFiles( _
startingdirectory & "\mydir\", "my.exe", IO.SearchOption.AllDirectories)

C#

string[] findedDirectories = IO.Directory.GetFiles( _
startingdirectory + "\\mydir\\", "my.exe", IO.SearchOption.AllDirectories);

Is it possible to stop searching after the first file is found in a way that the result of the function will be a string or an empty string, not a string array? Or is here better way to search for a first file in subdirectories?

Markus Safar
  • 6,324
  • 5
  • 28
  • 44
Wine Too
  • 4,515
  • 22
  • 83
  • 137
  • 1
    possible duplicate of [How to use DirectoryInfo.GetFiles and have it stop after finding the first match?](http://stackoverflow.com/questions/9120737/how-to-use-directoryinfo-getfiles-and-have-it-stop-after-finding-the-first-match) – Alex Filipovici Nov 01 '13 at 14:28
  • @AlexFilipovici It's not really a dupe of that since here we are looking for a single file in the directory. A simple call to `File.Exists` is sufficient. – David Heffernan Nov 01 '13 at 14:54
  • @DavidHeffernan: _...and go deep as needed..._ – Alex Filipovici Nov 01 '13 at 14:56
  • 1
    @AlexFilipovici OK, I suppose the overload of EnumerateFiles that takes a `SearchOption` parameter does what is required. – David Heffernan Nov 01 '13 at 15:00
  • My idea was to not use recursive scanning if DirectoryInfo is sufficient, but it is not. – Wine Too Nov 01 '13 at 20:00

2 Answers2

4

A solution like the following one could help:

/// <summary>
/// Searches for the first file matching to searchPattern in the sepcified path.
/// </summary>
/// <param name="path">The path from where to start the search.</param>
/// <param name="searchPattern">The pattern for which files to search for.</param>
/// <returns>Either the complete path including filename of the first file found
/// or string.Empty if no matching file could be found.</returns>
public static string FindFirstFile(string path, string searchPattern)
{
    string[] files;

    try
    {
        // Exception could occur due to insufficient permission.
        files = Directory.GetFiles(path, searchPattern, SearchOption.TopDirectoryOnly);
    }
    catch (Exception)
    {
        return string.Empty;
    }

    // If matching files have been found, return the first one.
    if (files.Length > 0)
    {
        return files[0];
    }
    else
    {
        // Otherwise find all directories.
        string[] directories;

        try
        {
            // Exception could occur due to insufficient permission.
            directories = Directory.GetDirectories(path);
        }
        catch (Exception)
        {
            return string.Empty;
        }

        // Iterate through each directory and call the method recursivly.
        foreach (string directory in directories)
        {
            string file = FindFirstFile(directory, searchPattern);

            // If we found a file, return it (and break the recursion).
            if (file != string.Empty)
            {
                return file;
            }
        }
    }

    // If no file was found (neither in this directory nor in the child directories)
    // simply return string.Empty.
    return string.Empty;
}
Markus Safar
  • 6,324
  • 5
  • 28
  • 44
2

I guess the simplest approach would be to organise the recursion into sub-directories yourself with recursive calls to Directory.GetDirectories passing SearchOption.TopDirectoryOnly. In each directory check for the file's existence with File.Exists.

This actually mirrors the way it would be done in Win32 with FindFirstFile. When using FindFirstFile you always need to implement the sub-directory recursion yourself because FindFirstFile has nothing analagous to SearchOption.AllDirectories.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490