.net Directory.EnumerateFiles=>;未经授权的访问例外
在.NET4.0中有一个很好的新方法,可以通过枚举以流方式获取目录中的文件 这里的问题是,如果希望枚举所有文件,可能事先不知道哪些文件或文件夹受访问保护,并且可能引发UnauthorizedAccessException 要复制,只需运行以下片段:.net Directory.EnumerateFiles=>;未经授权的访问例外,.net,filesystems,lazy-evaluation,unauthorizedaccessexcepti,.net,Filesystems,Lazy Evaluation,Unauthorizedaccessexcepti,在.NET4.0中有一个很好的新方法,可以通过枚举以流方式获取目录中的文件 这里的问题是,如果希望枚举所有文件,可能事先不知道哪些文件或文件夹受访问保护,并且可能引发UnauthorizedAccessException 要复制,只需运行以下片段: foreach (var file in Directory.EnumerateFiles(@"c:\", "*", SearchOption.AllDirectories)) { // whatever } 在这个.NET方法出现之前,通过
foreach (var file in Directory.EnumerateFiles(@"c:\", "*", SearchOption.AllDirectories))
{
// whatever
}
在这个.NET方法出现之前,通过在字符串数组返回方法上实现递归迭代器,可以实现大致相同的效果。但它并不像新的.NET方法那么懒惰
那怎么办呢?使用此方法时,是否可以抑制UnauthorizedAccessException,或者它是一个事实
在我看来,该方法应该有一个重载,接受处理任何异常的操作。我知道引发异常的是
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())
{
// ...
}
公共静态IEnumerable安全行走(此IEnumerable源代码)
{
var枚举器=source.GetEnumerator();
bool?hasCurrent=null;
做{
试一试{
hasCurrent=enumerator.MoveNext();
}抓住{
hasCurrent=null;//我们不确定
}
if(hasCurrent??false)//如果不确定,则不返回值
产生返回枚举数。当前;
}while(hasCurrent??true);//如果不确定,继续行走
}
foreach(目录.EnumerateFiles(“c:\\”、“*”、SearchOption.AllDirectory)中的var文件)
.SafeWalk())
{
// ...
}
只有当框架实现此迭代器的以下条件为真时,这才有效(请参阅Reflector中的FileSystemMemerableTerator
):
在失败时前进其位置李>MoveNext
- 当最后一个元素
失败时,后续调用将返回MoveNext
,而不是抛出异常李>false
- 对于不同版本的.NET Framework,此行为是一致的李>
- 我没有犯任何逻辑或语法错误
但是我真的很想知道它是否真的起作用。我无法让上面的内容起作用,但这是我的实现,我已经在“Win7”框中的c:\users上对它进行了测试,因为if有所有这些“讨厌的”目录: 类别:
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>();
}
}
}
公共静态类安全行走
{
公共静态IEnumerable枚举文件(字符串路径、字符串搜索模式、SearchOption searchOpt)
{
尝试
{
var dirFiles=Enumerable.Empty();
if(searchOpt==SearchOption.AllDirectories)
{
dirFiles=目录。枚举目录(路径)
.SelectMany(x=>枚举文件(x,searchPattern,searchOpt));
}
返回dirFiles.Concat(Directory.EnumerateFiles(path,searchPattern));
}
捕获(未经授权的访问例外)
{
返回可枚举的.Empty();
}
}
}
上述答案的问题是,不考虑子目录中的异常。这是处理这些异常的更好方法,因此您可以从所有子目录中获取所有文件,但存在访问异常的文件除外:
/// <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;
}
//
///获取目录和子目录中所有文件的安全方法,而不会因未经授权的异常或PathTooLongException而崩溃
///
///起始目录
///文件名模式匹配
///搜索子目录或仅搜索顶级目录中的文件
///文件清单
公共静态IEnumerable GetDirectoryFiles(字符串根路径、字符串模式匹配、搜索选项搜索选项)
{
var foundFiles=Enumerable.Empty();
if(searchOption==searchOption.AllDirectories)
{
尝试
{
IEnumerable subDirs=目录。枚举目录(根路径);
foreach(子目录中的字符串目录)
{
foundFiles=foundFiles.Concat(GetDirectoryFiles(dir,patternMatch,searchOption));//将子目录中的文件递归添加到列表中
}
}
捕获(UnauthorizedAccessException){}
catch(PathTooLongException){}
}
尝试
{
foundFiles=foundFiles.Concat(Directory.EnumerateFiles(rootPath,patternMatch));//从当前目录添加文件
}
捕获(UnauthorizedAccessException){}
归还文件;
}
我迟到了,但我建议改用可观察模式:
public class FileUtil
{
private static void FindFiles_(string path, string pattern,
SearchOption option, IObserver<string> obs, CancellationToken token)
{
try
{
foreach (var file in Directory.EnumerateFiles(path, pattern,
SearchOption.TopDirectoryOnly))
{
if (token.IsCancellationRequested) break;
obs.OnNext(file);
}
if (option != SearchOption.AllDirectories) return;
foreach (var dir in Directory.EnumerateDirectories(path, "*",
SearchOption.TopDirectoryOnly))
{
FindFiles_(dir, pattern, option, obs, token);
}
}
catch (UnauthorizedAccessException) { }
catch (PathTooLongException) { }
catch (IOException) { }
catch (Exception err) { obs.OnError(err); }
}
public static IObservable<string> GetFiles(string root, string pattern,
SearchOption option)
{
return Observable.Create<string>(
(obs, token) =>
Task.Factory.StartNew(
() =>
{
FindFiles_(root, pattern, option, obs, token);
obs.OnCompleted();
},
token));
}
}
公共类FileUtil
{
私有静态void FindFiles(字符串路径、字符串模式、,
SearchOption选项、IObserver obs、CancellationToken(令牌)
{
尝试
{
foreach(目录中的var文件。枚举文件(路径、模式、,
SearchOption.TopDirectoryOnly)
{
如果(token.IsCancellationRequested)中断;
obs.OnNext(文件);
}
if(option!=SearchOption.AllDirectories)返回;
foreach(目录中的var dir.EnumerateDirectories(路径“*”,
SearchOption.TopDirectoryOnly)
{
FindFiles(目录、模式、选项、obs、令牌);
}
}
捕获(UnauthorizedAccessException){}
catch(PathTooLongException){}
捕获(IOException){}
捕获(异常错误){obs.OnError(错误);}
}
公共静态IObservable GetFiles(字符串根、字符串模式、,
搜索选项(可选)
{
返回可观察的。创建(
(obs,令牌)=>
Task.Factory.StartNew(
() =>
{
FindF
public class FileUtil
{
private static void FindFiles_(string path, string pattern,
SearchOption option, IObserver<string> obs, CancellationToken token)
{
try
{
foreach (var file in Directory.EnumerateFiles(path, pattern,
SearchOption.TopDirectoryOnly))
{
if (token.IsCancellationRequested) break;
obs.OnNext(file);
}
if (option != SearchOption.AllDirectories) return;
foreach (var dir in Directory.EnumerateDirectories(path, "*",
SearchOption.TopDirectoryOnly))
{
FindFiles_(dir, pattern, option, obs, token);
}
}
catch (UnauthorizedAccessException) { }
catch (PathTooLongException) { }
catch (IOException) { }
catch (Exception err) { obs.OnError(err); }
}
public static IObservable<string> GetFiles(string root, string pattern,
SearchOption option)
{
return Observable.Create<string>(
(obs, token) =>
Task.Factory.StartNew(
() =>
{
FindFiles_(root, pattern, option, obs, token);
obs.OnCompleted();
},
token));
}
}
public static class SafeWalk
{
public static IEnumerable<string> EnumerateFiles(string path, string searchPattern, SearchOption searchOpt)
{
if (searchOpt == SearchOption.TopDirectoryOnly)
{
return Directory.EnumerateFiles(path, searchPattern, SearchOption.TopDirectoryOnly);
}
List<string> folders = new List<string>() { path };
int folCount = 1;
List<string> files = new List<string>() { };
for (int i = 0; i < folCount; i++)
{
try
{
foreach (var newDir in Directory.EnumerateDirectories(folders[i], "*", SearchOption.TopDirectoryOnly))
{
folders.Add(newDir);
folCount++;
try
{
foreach (var file in Directory.EnumerateFiles(newDir, searchPattern))
{
files.Add(file);
}
} catch (UnauthorizedAccessException)
{
// Failed to read a File, skipping it.
}
}
}
catch (UnauthorizedAccessException)
{
// Failed to read a Folder, skipping it.
continue;
}
}
return files;
}
}
static IEnumerable<string> FindFiles(string path, string filter = "*", bool recursive = false)
{
IEnumerator<string> fEnum;
try
{
fEnum = Directory.EnumerateFiles(path, filter, recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly).GetEnumerator();
}
catch (UnauthorizedAccessException) { yield break; }
while (true)
{
try { if (!fEnum.MoveNext()) break; }
catch (UnauthorizedAccessException) { continue; }
yield return fEnum.Current;
}
}