16

I'm running the code below and getting exception below. Am I forced to put this function in try catch or is there other way to get all directories recursively? I could write my own recursive function to get files and directory. But I wonder if there is a better way.

// get all files in folder and sub-folders
var d = Directory.GetFiles(@"C:\", "*", SearchOption.AllDirectories);

// get all sub-directories
var dirs = Directory.GetDirectories(@"C:\", "*", SearchOption.AllDirectories);

"Access to the path 'C:\Documents and Settings\' is denied."

0

7 Answers 7

38

If you want to continue with the next folder after a fail, then yea; you'll have to do it yourself. I would recommend a Stack<T> (depth first) or Queue<T> (bredth first) rather than recursion, and an iterator block (yield return); then you avoid both stack-overflow and memory usage issues.

Example:

    public static IEnumerable<string> GetFiles(string root, string searchPattern)
    {
        Stack<string> pending = new Stack<string>();
        pending.Push(root);
        while (pending.Count != 0)
        {
            var path = pending.Pop();
            string[] next = null;
            try
            {
                next = Directory.GetFiles(path, searchPattern);                    
            }
            catch { }
            if(next != null && next.Length != 0)
                foreach (var file in next) yield return file;
            try
            {
                next = Directory.GetDirectories(path);
                foreach (var subdir in next) pending.Push(subdir);
            }
            catch { }
        }
    }
5
  • 1
    +1 @Marc Thank you for giving alternative solution. Now that you gave me an alternative to recursion could you please provide with an example? Feb 13, 2011 at 20:07
  • This is really strange, but I can't debug your code. The debugger doesn't break on my break points, not even when I write Debugger.Break(); in your function. I kind of jump over you code. Feb 13, 2011 at 20:38
  • 1
    It seems to do with "yield return" Feb 13, 2011 at 20:41
  • 2
    @Amir - iterator blocks should still debug ok; but note that this is deferred execution; nothing happens until you call foreach to start iterating over it. And it'll only do one yield return per loop iteration (in the foreach). Feb 13, 2011 at 21:11
  • I had to call the function using foreach (string file in GetFiles(@"\\share\share", "*")) {//code here} to get it to execute. I'm green with C# and haven't used yield return before so it took some time to figure that out. This answer was super helpful all these years later!
    – Shrout1
    Jan 9, 2019 at 15:09
11

You can set the program so you can only run as administrator.

In Visual Studio:

Right click on the Project -> Properties -> Security -> Enable ClickOnce Security Settings

After you clicked it, a file will be created under the Project's properties folder called app.manifest once this is created, you can uncheck the Enable ClickOnce Security Settings option

Open that file and change this line :

<requestedExecutionLevel level="asInvoker" uiAccess="false" />

to:

 <requestedExecutionLevel  level="requireAdministrator" uiAccess="false" />

This will make the program require administrator privileges, and it will guarantee you have access to that folder.

4
  • +1 thats helpful to me too. Do you know how to tweak the clickonce so it would put an extra shortcut in the start menu that launched the app with admin? Feb 13, 2011 at 20:08
  • 1
    what about some folders protected by some applications you can't access them even as administrator access. Apr 20, 2013 at 13:03
  • ClickOnce and admin level aren't compatible. Don't know why +5
    – Nickon
    Jul 11, 2013 at 14:00
  • 1
    This didn't work for me. Despite using level="highestAvailable" in the manifest, I still get: "Access to the path 'C:\Users\captainawesome\AppData\Local\History' is denied."
    – Matt
    Oct 17, 2017 at 21:04
3

It has already been pointed out that you need to do it yourself so I thought I'd share my solution which avoids collections along the way. It should be noted that this will ignore all errors not just AccessDenied. To change that you can just make the catch blocks more specific.

    IEnumerable<string> GetFiles(string folder, string filter, bool recursive)
    {
        string [] found = null;
        try
        {
            found =  Directory.GetFiles(folder, filter);
        }
        catch { }
        if (found!=null)
            foreach (var x in found)
                yield return x;
        if (recursive)
        {
            found = null;
            try
            {
                found = Directory.GetDirectories(folder);
            }
            catch { }
            if (found != null)
                foreach (var x in found)
                    foreach (var y in GetFiles(x, filter, recursive))
                        yield return y;
        }
    }
3

You can achieve this by using EnumerationOptions for the third argument. This class provides a property called IgnoreInaccessible which toggles whether an exception will be thrown if an inaccessbile file/folder is encountered.

Other properties related to searching are available too, see: EnumerationOptions Class (System.IO)


Example:

var options = new EnumerationOptions()
{
    IgnoreInaccessible = true
};

var files = Directory.GetFiles("mypath", "*.*", options);

foreach (var file in files)
{
    // File related activities
}

Note: IgnoreAccessible is set to true by default, but I've included it in the example above for visibility purposes.

2
  • 1
    This class is not available in .NET Framework older than 5.0. Jun 4, 2020 at 8:18
  • 1
    This is also only available in .net core 2.1-6+ and NetStandard2.1 Feb 12, 2022 at 14:46
2

Well, you either avoid the directories for which you don't have permissions, or you don't but then respond gracefully when access is denied.

If you choose the first option, you will need to make sure that you know what directories they are, and also that the permissions for the thread's identity do not change. This is tricky and prone to error; I wouldn't recommend it for a production-quality system.

The second option looks more appropriate. Use a try/catch block and skip any "forbidden" directories.

1

I know this question is somewhat old, but I had this same problem today and I found the following article that explains a 'folder recursion' solution in detail.

The article acknowledges the flaws of the GetDirectories() method... :

Unfortunately, this [using the GetDirectories() method] has problems. Key amongst these is that some of the folders that you attempt to read could be configured so that the current user may not access them. Rather than ignoring folders to which you have restricted access, the method throws an UnauthorizedAccessException. However, we can circumvent this problem by creating our own recursive folder search code.

... and then introduces the solution in detail:

http://www.blackwasp.co.uk/FolderRecursion.aspx

0

This recursive method will return list of all files that are accessible in the folder.

    static List<string> getFilesInDir(string dirPath)
    {
        List<string> retVal = new List<string>();
        try
        {
            retVal = IO.Directory.GetFiles(dirPath, "*.*", IO.SearchOption.TopDirectoryOnly).ToList();
            foreach (IO.DirectoryInfo d in new IO.DirectoryInfo(dirPath).GetDirectories("*", IO.SearchOption.TopDirectoryOnly))
            {
                retVal.AddRange(getFilesInDir(d.FullName));
            }
        }
        catch (Exception ex)
        {
            //Console.WriteLine(dirPath);
        }
        return retVal;
    }

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