C# 当 Directory.GetFiles() 被拒绝访问时忽略文件夹/文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/172544/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 16:36:34  来源:igfitidea点击:

Ignore folders/files when Directory.GetFiles() is denied access

c#getfiles

提问by Rowan

I am trying to display a list of all files found in the selected directory (and optionally any subdirectories). The problem I am having is that when the GetFiles() method comes across a folder that it cannot access, it throws an exception and the process stops.

我正在尝试显示在所选目录(以及可选的任何子目录)中找到的所有文件的列表。我遇到的问题是,当 GetFiles() 方法遇到它无法访问的文件夹时,它会引发异常并且进程停止。

How do I ignore this exception (and ignore the protected folder/file) and continue adding accessible files to the list?

如何忽略此异常(并忽略受保护的文件夹/文件)并继续将可访问文件添加到列表中?

try
{
    if (cbSubFolders.Checked == false)
    {
        string[] files = Directory.GetFiles(folderBrowserDialog1.SelectedPath);
        foreach (string fileName in files)
            ProcessFile(fileName);
    }
    else
    {
        string[] files = Directory.GetFiles(folderBrowserDialog1.SelectedPath, "*.*", SearchOption.AllDirectories);
        foreach (string fileName in files)
            ProcessFile(fileName);
    }
    lblNumberOfFilesDisplay.Enabled = true;
}
catch (UnauthorizedAccessException) { }
finally {}

采纳答案by Marc Gravell

You will have to do the recursion manually; don't use AllDirectories - look one folder at a time, then try getting the files from sub-dirs. Untested, but something like below (note uses a delegate rather than building an array):

您必须手动执行递归;不要使用 AllDirectories - 一次查看一个文件夹,然后尝试从子目录中获取文件。未经测试,但类似于以下内容(注意使用委托而不是构建数组):

using System;
using System.IO;
static class Program
{
    static void Main()
    {
        string path = ""; // TODO
        ApplyAllFiles(path, ProcessFile);
    }
    static void ProcessFile(string path) {/* ... */}
    static void ApplyAllFiles(string folder, Action<string> fileAction)
    {
        foreach (string file in Directory.GetFiles(folder))
        {
            fileAction(file);
        }
        foreach (string subDir in Directory.GetDirectories(folder))
        {
            try
            {
                ApplyAllFiles(subDir, fileAction);
            }
            catch
            {
                // swallow, log, whatever
            }
        }
    }
}

回答by user25306

This should answer the question. I've ignored the issue of going through subdirectories, I'm assuming you have that figured out.

这应该回答这个问题。我忽略了通过子目录的问题,我假设你已经弄清楚了。

Of course, you don't need to have a seperate method for this, but you might find it a useful place to also verify the path is valid, and deal with the other exceptions that you could encounter when calling GetFiles().

当然,您不需要为此使用单独的方法,但您可能会发现这是一个有用的地方,可以验证路径是否有效,并处理调用 GetFiles() 时可能遇到的其他异常。

Hope this helps.

希望这可以帮助。

private string[] GetFiles(string path)
{
    string[] files = null;
    try
    {
       files = Directory.GetFiles(path);
    }
    catch (UnauthorizedAccessException)
    {
       // might be nice to log this, or something ...
    }

    return files;
}

private void Processor(string path, bool recursive)
{
    // leaving the recursive directory navigation out.
    string[] files = this.GetFiles(path);
    if (null != files)
    {
        foreach (string file in files)
        {
           this.Process(file);
        }
    }
    else
    {
       // again, might want to do something when you can't access the path?
    }
}

回答by user25306

回答by Malcolm

see https://stackoverflow.com/a/10728792/89584for a solution that handles the UnauthorisedAccessException problem.

有关处理 UnauthorisedAccessException 问题的解决方案,请参阅https://stackoverflow.com/a/10728792/89584

All the solutions above will miss files and/or directories if any calls to GetFiles() or GetDirectories() are on folders with a mix of permissions.

如果对 GetFiles() 或 GetDirectories() 的任何调用位于具有混合权限的文件夹上,则上述所有解决方案都将丢失文件和/或目录。

回答by sergeidave

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... :

文章承认该GetDirectories()方法的缺陷......:

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.

不幸的是,这 [使用 GetDirectories() 方法] 有问题。其中的关键是您尝试读取的某些文件夹可以配置为当前用户可能无法访问它们。该方法不会忽略您限制访问的文件夹,而是抛出 UnauthorizedAccessException。但是,我们可以通过创建自己的递归文件夹搜索代码来规避这个问题。

... and then introduces the solution in detail:

...然后详细介绍解决方案:

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

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

回答by Ben Gripka

This simple function works well and meets the questions requirements.

这个简单的功能运行良好,满足问题要求。

private List<string> GetFiles(string path, string pattern)
{
    var files = new List<string>();

    try 
    { 
        files.AddRange(Directory.GetFiles(path, pattern, SearchOption.TopDirectoryOnly));
        foreach (var directory in Directory.GetDirectories(path))
            files.AddRange(GetFiles(directory, pattern));
    } 
    catch (UnauthorizedAccessException) { }

    return files;
}

回答by Shubham

A simple way to do this is by using a List for files and a Queue for directories. It conserves memory. If you use a recursive program to do the same task, that could throw OutOfMemory exception. The output: files added in the List, are organised according to the top to bottom (breadth first) directory tree.

一种简单的方法是使用文件列表和目录队列。它节省了内存。如果您使用递归程序来执行相同的任务,则可能会抛出 OutOfMemory 异常。输出:列表中添加的文件,按照从上到下(广度优先)的目录树进行组织。

public static List<string> GetAllFilesFromFolder(string root, bool searchSubfolders) {
    Queue<string> folders = new Queue<string>();
    List<string> files = new List<string>();
    folders.Enqueue(root);
    while (folders.Count != 0) {
        string currentFolder = folders.Dequeue();
        try {
            string[] filesInCurrent = System.IO.Directory.GetFiles(currentFolder, "*.*", System.IO.SearchOption.TopDirectoryOnly);
            files.AddRange(filesInCurrent);
        }
        catch {
            // Do Nothing
        }
        try {
            if (searchSubfolders) {
                string[] foldersInCurrent = System.IO.Directory.GetDirectories(currentFolder, "*.*", System.IO.SearchOption.TopDirectoryOnly);
                foreach (string _current in foldersInCurrent) {
                    folders.Enqueue(_current);
                }
            }
        }
        catch {
            // Do Nothing
        }
    }
    return files;
}

Steps:

脚步:

  1. Enqueue the root in the queue
  2. In a loop, Dequeue it, Add the files in that directory to the list, and Add the subfolders to the queue.
  3. Repeat untill the queue is empty.
  1. 将根加入队列
  2. 在循环中,将其出列,将该目录中的文件添加到列表中,并将子文件夹添加到队列中。
  3. 重复直到队列为空。

回答by user541686

Here's a full-featured, .NET 2.0-compatible implementation.

这是一个功能齐全、与 .NET 2.0 兼容的实现。

You can even alter the yielded Listof files to skip over directories in the FileSystemInfoversion!

您甚至可以更改生成List的文件以跳过FileSystemInfo版本中的目录!

(Beware nullvalues!)

(当心null值!)

public static IEnumerable<KeyValuePair<string, string[]>> GetFileSystemInfosRecursive(string dir, bool depth_first)
{
    foreach (var item in GetFileSystemObjectsRecursive(new DirectoryInfo(dir), depth_first))
    {
        string[] result;
        var children = item.Value;
        if (children != null)
        {
            result = new string[children.Count];
            for (int i = 0; i < result.Length; i++)
            { result[i] = children[i].Name; }
        }
        else { result = null; }
        string fullname;
        try { fullname = item.Key.FullName; }
        catch (IOException) { fullname = null; }
        catch (UnauthorizedAccessException) { fullname = null; }
        yield return new KeyValuePair<string, string[]>(fullname, result);
    }
}

public static IEnumerable<KeyValuePair<DirectoryInfo, List<FileSystemInfo>>> GetFileSystemInfosRecursive(DirectoryInfo dir, bool depth_first)
{
    var stack = depth_first ? new Stack<DirectoryInfo>() : null;
    var queue = depth_first ? null : new Queue<DirectoryInfo>();
    if (depth_first) { stack.Push(dir); }
    else { queue.Enqueue(dir); }
    for (var list = new List<FileSystemInfo>(); (depth_first ? stack.Count : queue.Count) > 0; list.Clear())
    {
        dir = depth_first ? stack.Pop() : queue.Dequeue();
        FileSystemInfo[] children;
        try { children = dir.GetFileSystemInfos(); }
        catch (UnauthorizedAccessException) { children = null; }
        catch (IOException) { children = null; }
        if (children != null) { list.AddRange(children); }
        yield return new KeyValuePair<DirectoryInfo, List<FileSystemInfo>>(dir, children != null ? list : null);
        if (depth_first) { list.Reverse(); }
        foreach (var child in list)
        {
            var asdir = child as DirectoryInfo;
            if (asdir != null)
            {
                if (depth_first) { stack.Push(asdir); }
                else { queue.Enqueue(asdir); }
            }
        }
    }
}

回答by Shahin Dohan

Since .NET Standard 2.1, you can now just do:

从 .NET Standard 2.1 开始,您现在可以执行以下操作:

var filePaths = Directory.EnumerateFiles(@"C:\my\files", "*.xml", new EnumerationOptions
{
    IgnoreInaccessible = true,
    RecurseSubdirectories = true
});

According to the MSDN docsabout IgnoreInaccessible:

根据关于IgnoreInaccessibleMSDN 文档

Gets or sets a value that indicates whether to skip files or directories when access is denied (for example, UnauthorizedAccessException or SecurityException). The default is true.

获取或设置一个值,该值指示在拒绝访问时是否跳过文件或目录(例如,UnauthorizedAccessException 或 SecurityException)。默认值为真。

Default value is actually true, but I've kept it here just to show the property.

默认值实际上是 true,但我将它保留在这里只是为了显示属性。

The same overload is available for DirectoryInfoas well.

同样的重载也可用于DirectoryInfo