7
\$\begingroup\$

I have a files search function that iterates over a given directory until a given depth is reached and returns the found files. I did this via the Enumerate methods of the Directory class and yield return the results. Since it's very likely that I hit a directory that I can't access (e.g. system directories) or generate a too long path (if the depth is large), I have to catch the exceptions from these cases. However since I can't use yield in try/catch statements, I find my code pretty bloated, because I have to seperate the critical method calls from the rest.

Is there a better/shorter way to do this, or are there best practices for that case?

private IEnumerable<string> SearchSubdirs(string currentDir, int currentDepth) {

    IEnumerable<string> exeFiles;
    try {
        exeFiles = Directory.EnumerateFiles(currentDir, "*.exe");
    }
    catch (UnauthorizedAccessException uae) {
        Debug.WriteLine(uae.Message);
        yield break;
    }
    catch (PathTooLongException ptle) {
        Debug.WriteLine(ptle.Message);
        yield break;
    }

    foreach (string currentFile in exeFiles) {

        // Ignore unistaller *.exe files
        if (currentFile.IndexOf("unins", 0, StringComparison.CurrentCultureIgnoreCase) == -1) {
            yield return currentFile;
        }
    }

    if (currentDepth < maxDepth) {
        IEnumerable<string> subDirectories;
        currentDepth++;
        try {
            subDirectories = Directory.EnumerateDirectories(currentDir);
        }
        catch (UnauthorizedAccessException uae) {
            Debug.WriteLine(uae.Message);
            yield break;
        }
        catch (PathTooLongException ptle) {
            Debug.WriteLine(ptle.Message);
            yield break;
        }

        foreach (string subDir in subDirectories) {
            foreach (string file in SearchSubdirs(subDir, currentDepth)) {
                yield return file;
            }
        }
    }
}
| improve this question | | | | |
\$\endgroup\$
5
+50
\$\begingroup\$

I would use Linq methods to simplify the code. Also I've extracted 2 methods to simplify the main method. And please rename GetFilesWeAreLookingFor to whatever your find appropriate :).

private static IEnumerable<string> GetFilesWeAreLookingFor(string currentDir)
{
    try
    {
        return Directory.EnumerateFiles(currentDir, "*.exe")
            .Where(fileName => fileName.IndexOf("unins", 0, StringComparison.CurrentCultureIgnoreCase) == -1);
    }
    catch (UnauthorizedAccessException uae)
    {
        Debug.WriteLine(uae.Message);
    }
    catch (PathTooLongException ptle)
    {
        Debug.WriteLine(ptle.Message);
    }
    return Enumerable.Empty<string>();
}

private IEnumerable<string> GetNestedFiles(string currentDir, int nestedDepth)
{
    try
    {
        return Directory.EnumerateDirectories(currentDir)
            .SelectMany(subDirectory => SearchSubdirs(subDirectory, nestedDepth));
    }
    catch (UnauthorizedAccessException uae)
    {
        Debug.WriteLine(uae.Message);
    }
    catch (PathTooLongException ptle)
    {
        Debug.WriteLine(ptle.Message);
    }
    return Enumerable.Empty<string>();
}

private IEnumerable<string> SearchSubdirs(string currentDir, int currentDepth)
{
    IEnumerable<string> filesWeAreLookingFor = GetFilesWeAreLookingFor(currentDir);

    if (currentDepth < _maxDepth)
        filesWeAreLookingFor = filesWeAreLookingFor.Concat(GetNestedFiles(currentDir, currentDepth + 1));

    return filesWeAreLookingFor;
}
| improve this answer | | | | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.