Directory.EnumerateFiles => UnauthorizedAccessExceptionEnumerateFiles、Directory、UnauthorizedAcces

2023-09-02 10:35:01 作者:毁灭人格

有通过枚举获取目录中的文件以流的方式在.NET 4.0中一个不错的新方法。

There is a nice new method in .NET 4.0 for getting files in a directory in a streaming way via enumeration.

这里的问题是,如果一个人希望枚举所有文件之一可能不会提前知道哪些文件或文件夹的访问权限保护,可以抛出UnauthorizedAccessException。

The problem here is that if one wishes to enumerate all files one may not know in advance which files or folders are access protected and can throw an UnauthorizedAccessException.

要重现,人们可以直接运行这个片断:

To reproduce, one can just run this fragment:

foreach (var file in Directory.EnumerateFiles(@"c:", "*", SearchOption.AllDirectories))
{
   // whatever
}

在此.NET方法存在有可能实现大致通过实现串阵列返回的方法上递归迭代相同的效果。但是,这不是很懒惰的新的.NET方法。

Before this .NET method existed it was possible to achieve roughly the same effect by implementing a recursive iterator on the string-array returning methods. But it's not quite as lazy as the new .NET method is.

那么怎么办?能否UnauthorizedAccessException是燮pressed或者是生活中的事实,使用这种方法的时候?

So what to do? Can the UnauthorizedAccessException be suppressed or is a fact of life when using this method?

在我看来,该方法应该有一个重载接受一个行动,以应付任何异常。

Seems to me that the method should have an overload accepting an action to deal with any exceptions.

推荐答案

THS问题上面的回答是不照顾例外的子目录。这将是一个更好的方式来处理这些异常,所以你从所有子目录下的所有文件,除了那些抛出访问异常:

Ths issue with the above answer is that is does not take care of exception in sub directories. This would be a better way to handling those exceptions so you get ALL files from ALL subdirectories except those with threw an access exception:

    /// <summary>
    /// A safe way to get all the files in a directory and sub directory without crashing on UnauthorizedException or PathTooLongException
    /// </summary>
    /// <param name="rootPath">Starting directory</param>
    /// <param name="patternMatch">Filename pattern match</param>
    /// <param name="searchOption">Search subdirectories or only top level directory for files</param>
    /// <returns>List of files</returns>
    public static IEnumerable<string> GetDirectoryFiles(string rootPath, string patternMatch, SearchOption searchOption)
    {
        var foundFiles = Enumerable.Empty<string>();

        if (searchOption == SearchOption.AllDirectories)
        {
            try
            {
                IEnumerable<string> subDirs = Directory.EnumerateDirectories(rootPath);
                foreach (string dir in subDirs)
                {
                    foundFiles = foundFiles.Concat(GetDirectoryFiles(dir, patternMatch, searchOption)); // Add files in subdirectories recursively to the list
                }
            }
            catch (UnauthorizedAccessException) { }
            catch (PathTooLongException) {}
        }

        try
        {
            foundFiles = foundFiles.Concat(Directory.EnumerateFiles(rootPath, patternMatch)); // Add files from the current directory
        }
        catch (UnauthorizedAccessException) { }

        return foundFiles;
    }