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

发布于 2024-07-06 08:37:26 字数 696 浏览 5 评论 0原文

我试图显示在所选目录(以及可选的任何子目录)中找到的所有文件的列表。 我遇到的问题是,当 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 {}

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.

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 {}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

骷髅 2024-07-13 08:37:26

您必须手动进行递归; 不要使用 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
            }
        }
    }
}

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

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
            }
        }
    }
}
没︽人懂的悲伤 2024-07-13 08:37:26

从 .NET Standard 2.1(.NET Core 3+、.NET 5+)开始,您现在可以执行以下操作:

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

根据 MSDN 文档 关于 IgnoreInaccessible

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

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

相同的重载也可用于 DirectoryInfo

Since .NET Standard 2.1 (.NET Core 3+, .NET 5+), you can now just do:

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

According to the MSDN docs about IgnoreInaccessible:

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.

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

The same overload is available for DirectoryInfo as well.

梦太阳 2024-07-13 08:37:26

这个简单的函数效果很好,满足了题目的要求。

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

    try
    {
        files.AddRange(Directory.GetFiles(path, pattern, SearchOption.TopDirectoryOnly));
        directories = Directory.GetDirectories(path);
    }
    catch (UnauthorizedAccessException) { }

    foreach (var directory in directories)
        try
        {
            files.AddRange(GetFiles(directory, pattern));
        }
        catch (UnauthorizedAccessException) { }

    return files;
}

This simple function works well and meets the questions requirements.

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

    try
    {
        files.AddRange(Directory.GetFiles(path, pattern, SearchOption.TopDirectoryOnly));
        directories = Directory.GetDirectories(path);
    }
    catch (UnauthorizedAccessException) { }

    foreach (var directory in directories)
        try
        {
            files.AddRange(GetFiles(directory, pattern));
        }
        catch (UnauthorizedAccessException) { }

    return files;
}
弥枳 2024-07-13 08:37:26

执行此操作的一个简单方法是使用文件列表和目录队列。
它节省内存。
如果您使用递归程序来执行相同的任务,则可能会引发 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;
}

步骤:

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

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.

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.
别忘他 2024-07-13 08:37:26

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

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

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

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.

冬天的雪花 2024-07-13 08:37:26

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

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

(注意 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); }
            }
        }
    }
}

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

You can even alter the yielded List of files to skip over directories in the FileSystemInfo version!

(Beware null values!)

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); }
            }
        }
    }
}
晒暮凉 2024-07-13 08:37:26

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

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

希望这可以帮助。

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?
    }
}

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().

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?
    }
}
メ斷腸人バ 2024-07-13 08:37:26

我更喜欢使用c#框架函数,但是我需要的函数将包含在.net框架5.0中,所以我必须编写它。

// search file in every subdirectory ignoring access errors
    static List<string> list_files(string path)
    {
        List<string> files = new List<string>();

        // add the files in the current directory
        try
        {
            string[] entries = Directory.GetFiles(path);

            foreach (string entry in entries)
                files.Add(System.IO.Path.Combine(path,entry));
        }
        catch 
        { 
        // an exception in directory.getfiles is not recoverable: the directory is not accessible
        }

        // follow the subdirectories
        try
        {
            string[] entries = Directory.GetDirectories(path);

            foreach (string entry in entries)
            {
                string current_path = System.IO.Path.Combine(path, entry);
                List<string> files_in_subdir = list_files(current_path);

                foreach (string current_file in files_in_subdir)
                    files.Add(current_file);
            }
        }
        catch
        {
            // an exception in directory.getdirectories is not recoverable: the directory is not accessible
        }

        return files;
    }

I prefer using c# framework functions, but the function i need will be included in .net framework 5.0, so i have to write it.

// search file in every subdirectory ignoring access errors
    static List<string> list_files(string path)
    {
        List<string> files = new List<string>();

        // add the files in the current directory
        try
        {
            string[] entries = Directory.GetFiles(path);

            foreach (string entry in entries)
                files.Add(System.IO.Path.Combine(path,entry));
        }
        catch 
        { 
        // an exception in directory.getfiles is not recoverable: the directory is not accessible
        }

        // follow the subdirectories
        try
        {
            string[] entries = Directory.GetDirectories(path);

            foreach (string entry in entries)
            {
                string current_path = System.IO.Path.Combine(path, entry);
                List<string> files_in_subdir = list_files(current_path);

                foreach (string current_file in files_in_subdir)
                    files.Add(current_file);
            }
        }
        catch
        {
            // an exception in directory.getdirectories is not recoverable: the directory is not accessible
        }

        return files;
    }
扬花落满肩 2024-07-13 08:37:26

对于那些目标框架低于 NET 2.1 的人,只需在 nuget 上获取 Microsoft.IO.Redist 即可。

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

For those who target framework is bellow NET 2.1 just get Microsoft.IO.Redist on nuget.

var filePaths = Directory.EnumerateFiles(@"C:\my\files", "*.xml", new EnumerationOptions
{
    IgnoreInaccessible = true,
    RecurseSubdirectories = true
});
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文