Ben*_*sen 37 .net filesystems lazy-evaluation unauthorizedaccessexcepti
.NET 4.0中有一个很好的新方法,可以通过枚举以流方式获取目录中的文件.
这里的问题是,如果想要枚举所有文件,可能事先不知道哪些文件或文件夹受到访问保护并且可能抛出UnauthorizedAccessException.
要重现,可以运行此片段:
foreach (var file in Directory.EnumerateFiles(@"c:\", "*", SearchOption.AllDirectories))
{
// whatever
}
Run Code Online (Sandbox Code Playgroud)
在此.NET方法存在之前,通过在字符串数组返回方法上实现递归迭代器,可以实现大致相同的效果.但它并不像新的.NET方法那么懒惰.
那么该怎么办?使用此方法时,UnauthorizedAccessException可以被抑制还是生活中的事实?
在我看来,该方法应该有一个重载接受一个动作来处理任何异常.
str*_*dso 29
我无法完成上述工作,但这是我的实现,我已经在"Win7"盒子上的c:\ users上进行了测试,因为如果有所有这些"令人讨厌"的目录:
SafeWalk.EnumerateFiles(@"C:\users", "*.jpg", SearchOption.AllDirectories).Take(10)
Run Code Online (Sandbox Code Playgroud)
类:
public static class SafeWalk
{
public static IEnumerable<string> EnumerateFiles(string path, string searchPattern, SearchOption searchOpt)
{
try
{
var dirFiles = Enumerable.Empty<string>();
if(searchOpt == SearchOption.AllDirectories)
{
dirFiles = Directory.EnumerateDirectories(path)
.SelectMany(x => EnumerateFiles(x, searchPattern, searchOpt));
}
return dirFiles.Concat(Directory.EnumerateFiles(path, searchPattern));
}
catch(UnauthorizedAccessException ex)
{
return Enumerable.Empty<string>();
}
}
}
Run Code Online (Sandbox Code Playgroud)
小智 8
上述答案的问题是在子目录中没有处理异常.这将是处理这些异常的更好方法,因此您可以从所有子目录获取所有文件,除了那些引发访问异常的文件:
/// <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;
}
Run Code Online (Sandbox Code Playgroud)
我知道这MoveNext是抛出异常。
我试图编写一个安全遍历序列并尝试忽略MoveNext异常的方法。但是我不确定MoveNext当它抛出异常时是否提前位置,所以这也可能是无限循环。这也是个坏主意,因为我们将依赖于实现细节。
但这真是太有趣了!
public static IEnumerable<T> SafeWalk<T> (this IEnumerable<T> source)
{
var enumerator = source.GetEnumerator();
bool? hasCurrent = null;
do {
try {
hasCurrent = enumerator.MoveNext();
} catch {
hasCurrent = null; // we're not sure
}
if (hasCurrent ?? false) // if not sure, do not return value
yield return enumerator.Current;
} while (hasCurrent ?? true); // if not sure, continue walking
}
foreach (var file in Directory.EnumerateFiles("c:\\", "*", SearchOption.AllDirectories)
.SafeWalk())
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
这仅在框架实现此迭代器的以下条件为真时才有效(参见FileSystemEnumerableIterator<TSource>Reflector 以供参考):
MoveNext 失败时推进其位置;MoveNext最后一个元素失败时,后续调用将返回false而不是抛出异常;即使它有效,也请不要在生产中使用它!
但我真的想知道它是否确实如此。
| 归档时间: |
|
| 查看次数: |
13553 次 |
| 最近记录: |