DirectoryInfo.EnumerateFiles(…)导致UnauthorizedAccessException(和其他exception)

我最近需要枚举整个文件系统,以查找特定类型的文件以进行审计。 由于对要扫描的文件系统的权限有限,这导致我遇到几个例外。 其中,最流行的是UnauthorizedAccessException以及我的懊恼, PathTooLongException 。

这些通常不是问题,除了它们使IEnumerable无效,使我无法完成扫描。

为了解决这个问题,我创建了一个替换文件系统枚举器。 虽然它可能不完美,但它的执行速度相当快,并且陷入了我遇到的两个例外。 它将找到与传递给它的搜索模式匹配的任何目录或文件。

// This code is public domain using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using log4net; public class FileSystemEnumerable : IEnumerable { private ILog _logger = LogManager.GetLogger(typeof(FileSystemEnumerable)); private readonly DirectoryInfo _root; private readonly IList _patterns; private readonly SearchOption _option; public FileSystemEnumerable(DirectoryInfo root, string pattern, SearchOption option) { _root = root; _patterns = new List { pattern }; _option = option; } public FileSystemEnumerable(DirectoryInfo root, IList patterns, SearchOption option) { _root = root; _patterns = patterns; _option = option; } public IEnumerator GetEnumerator() { if (_root == null || !_root.Exists) yield break; IEnumerable matches = new List(); try { _logger.DebugFormat("Attempting to enumerate '{0}'", _root.FullName); foreach (var pattern in _patterns) { _logger.DebugFormat("Using pattern '{0}'", pattern); matches = matches.Concat(_root.EnumerateDirectories(pattern, SearchOption.TopDirectoryOnly)) .Concat(_root.EnumerateFiles(pattern, SearchOption.TopDirectoryOnly)); } } catch (UnauthorizedAccessException) { _logger.WarnFormat("Unable to access '{0}'. Skipping...", _root.FullName); yield break; } catch (PathTooLongException ptle) { _logger.Warn(string.Format(@"Could not process path '{0}\{1}'.", _root.Parent.FullName, _root.Name), ptle); yield break; } catch (System.IO.IOException e) { // "The symbolic link cannot be followed because its type is disabled." // "The specified network name is no longer available." _logger.Warn(string.Format(@"Could not process path (check SymlinkEvaluation rules)'{0}\{1}'.", _root.Parent.FullName, _root.Name), e); yield break; } _logger.DebugFormat("Returning all objects that match the pattern(s) '{0}'", string.Join(",", _patterns)); foreach (var file in matches) { yield return file; } if (_option == SearchOption.AllDirectories) { _logger.DebugFormat("Enumerating all child directories."); foreach (var dir in _root.EnumerateDirectories("*", SearchOption.TopDirectoryOnly)) { _logger.DebugFormat("Enumerating '{0}'", dir.FullName); var fileSystemInfos = new FileSystemEnumerable(dir, _patterns, _option); foreach (var match in fileSystemInfos) { yield return match; } } } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } 

用法很简单。

 //This code is public domain var root = new DirectoryInfo(@"c:\wherever"); var searchPattern = @"*.txt"; var searchOption = SearchOption.AllDirectories; var enumerable = new FileSystemEnumerable(root, searchPattern, searchOption); 

如果人们发现它有用,他们可以自由使用它。

这是另一种方法,管理自己的枚举迭代:

 IEnumerator errFiles=Directory.EnumerateFiles(baseDir, "_error.txt", SearchOption.AllDirectories).GetEnumerator(); while (true) { try { if (!errFiles.MoveNext()) break; string errFile = errFiles.Current; // processing } catch (Exception e) { log.Warn("Ignoring error finding in: " + baseDir, e); } }