Getting files recursively: skip files/directories that cannot be read?

Viewed 3828

I want to get all of the files in a directory in an array (including the files in subfolders)

string[] filePaths = Directory.GetFiles(@"c:\",SearchOption.AllDirectories);     

The problem with this is: If an exception is thrown the entire command stops. Is there a better way to do this so that if a folder cannot be accessed it will just skip over it?

4 Answers

Directory.GetFiles can't skip directory symbol links which often cause loops and then exceptions.

So based on @iks's answer and Check if a file is real or a symbolic link, here is a version that deliver the result on the go like Directory.EnumerateFiles does:

    public static IEnumerable<string> FindAllFiles(string rootDir)
    {
        var pathsToSearch = new Queue<string>();


        pathsToSearch.Enqueue(rootDir);

        while (pathsToSearch.Count > 0)
        {
            var dir = pathsToSearch.Dequeue();
            var foundFiles = new List<string>();
            try
            {
                foreach (var file in Directory.GetFiles(dir))
                    foundFiles.Add(file);

                foreach (var subDir in Directory.GetDirectories(dir))
                {
                    //comment this if want to follow symbolic link
                    //or follow them conditionally
                    if (IsSymbolic(subDir)) continue;
                    pathsToSearch.Enqueue(subDir);
                }
            }
            catch (Exception) {//deal with exceptions here
            }
            foreach (var file in foundFiles) yield return file;
        } 


    }

    static private bool IsSymbolic(string path)
    {
        FileInfo pathInfo = new FileInfo(path);
        return pathInfo.Attributes.HasFlag(System.IO.FileAttributes.ReparsePoint);
    }

    static public void test()
    {
        string root = @"D:\root";
        foreach (var fn in FindAllFiles(root)
            .Where(x=>
            true    //filter condition here
            ))
        {
            Debug.WriteLine(fn);
        }
    }
Related