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

Row*_*wan 71 c# getfiles

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

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

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 {}
Run Code Online (Sandbox Code Playgroud)

Mar*_*ell 48

你必须手动进行递归; 不要使用AllDirectories - 一次查看一个文件夹,然后尝试从sub-dirs获取文件.未经测试,但如下所示(注意使用委托而不是构建数组):

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
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 仍然不够:当文件夹中只有一个文件不可访问时,GetFiles会在内部抛出.因此整个文件夹将不予处理. (4认同)

Ben*_*pka 13

这个简单的功能很好,满足了问题的要求.

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;
}
Run Code Online (Sandbox Code Playgroud)


Sha*_*han 9

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

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

根据关于IgnoreInaccessibleMSDN 文档

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

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

同样的重载也可用于DirectoryInfo

  • 此函数重载也包含在 NET 5 和 NET 6 RC 2 中。 (2认同)

小智 5

一种简单的方法是使用文件列表和目录队列。它可以节省内存。如果您使用递归程序执行相同的任务,则可能会抛出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;
}
Run Code Online (Sandbox Code Playgroud)

脚步:

  1. 将根加入队列
  2. 在循环中,将其出队,将该目录中的文件添加到列表,然后将子文件夹添加到队列。
  3. 重复直到队列为空。