在枚举时,我想跳过/忽略异常。
我尝试在选择器中添加一个try catch:
static IEnumerable<string> GetSafeAllFiles
(string path, string searchPattern, SearchOption searchOption = SearchOption.AllDirectories)
{
return Directory.EnumerateFiles(path, searchPattern, searchOption)
.Select(f =>
{
try
{
return f;
}
catch (Exception e)
{
return string.Empty;
}
});
}
我尝试使用accepted answer中的解决方案:
var test23 = Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories)
.SkipExceptions().Take(100);
没有结果,因为它将在第一个错误后停止。所以我尝试实现自己的:
static IEnumerable<string> test12(string path, string searchPattern, SearchOption searchOption = SearchOption.AllDirectories)
{
if (string.IsNullOrEmpty(path))
{
throw new ArgumentNullException("path");
}
if (string.IsNullOrEmpty(searchPattern))
{
throw new ArgumentNullException("searchPattern");
}
Queue<string> stillToProcess = new Queue<string>(new[] { path });
foreach (var dir in Directory.EnumerateDirectories(path))
{
stillToProcess.Enqueue(dir);
}
while (stillToProcess.Count > 0)
{
string currentPath = stillToProcess.Dequeue();
IEnumerable<string> ret = Enumerable.Empty<string>();
try
{
ret = Directory.EnumerateFiles(currentPath, searchPattern);
}
catch (UnauthorizedAccessException e)
{ }
// yield! keyword
foreach (var i in ret) { yield return i; }
}
yield break;
}
但是如果有一个错误,它将跳过目录。当我只想跳过错误文件时。
为了进行测试,可能的解决方案请在c:\$Recycle.Bin
上进行操作,因为它是UnauthorizedAccessException
的最简单来源。
答案 0 :(得分:0)
有时候,我编写了这段代码,以获取目录和所有子目录中的所有文件。我会以这种方式实现您的目标。您必须对其进行自定义才能与搜索模式和搜索选项一起使用。否则,通过防止代码整体抛出异常,CanRead方法可以解决您的问题。
public class DirectoryAnalyser
{
private List<string> _files;
private int _directoryCounter;
public async Task<List<string>> GetFilesAsync(string directory, CancellationTokenSource cancellationToken, IProgress<DirectoryAnalyserProgress> progress)
{
this._files = new List<string>();
this._directoryCounter = 0;
await this.GetFilesInternalAsync(directory, cancellationToken, progress);
return this._files;
}
private async Task GetFilesInternalAsync(string directory, CancellationTokenSource cancellationToken, IProgress<DirectoryAnalyserProgress> progress)
{
if (cancellationToken.IsCancellationRequested)
{
return;
}
if (!this.CanRead(directory))
{
return;
}
this._files.AddRange(Directory.GetFiles(directory));
this._directoryCounter++;
progress?.Report(new DirectoryAnalyserProgress()
{
DirectoriesSearched = this._directoryCounter,
FilesFound = this._files.Count
});
foreach (var subDirectory in Directory.GetDirectories(directory))
{
await this.GetFilesInternalAsync(subDirectory, cancellationToken, progress);
}
}
public bool CanRead(string path)
{
var readAllow = false;
var readDeny = false;
var accessControlList = Directory.GetAccessControl(path);
if (accessControlList == null)
{
return false;
}
var accessRules = accessControlList.GetAccessRules(true, true, typeof(SecurityIdentifier));
if (accessRules == null)
{
return false;
}
foreach (FileSystemAccessRule rule in accessRules)
{
if ((FileSystemRights.Read & rule.FileSystemRights) != FileSystemRights.Read)
{
continue;
}
if (rule.AccessControlType == AccessControlType.Allow)
{
readAllow = true;
}
else if (rule.AccessControlType == AccessControlType.Deny)
{
readDeny = true;
}
}
return readAllow && !readDeny;
}
}
public class DirectoryAnalyserProgress
{
public int FilesFound { get; set; }
public int DirectoriesSearched { get; set; }
}