我最近需要枚举一个整个文件系统,寻找特定类型的文件进行审计.由于对要扫描的文件系统的权限有限,这导致我遇到了几个例外.其中最流行的是
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<FileSystemInfo>
- {
- private ILog _logger = LogManager.GetLogger(typeof(FileSystemEnumerable));
- private readonly DirectoryInfo _root;
- private readonly IList<string> _patterns;
- private readonly SearchOption _option;
- public FileSystemEnumerable(DirectoryInfo root,string pattern,SearchOption option)
- {
- _root = root;
- _patterns = new List<string> { pattern };
- _option = option;
- }
- public FileSystemEnumerable(DirectoryInfo root,IList<string> patterns,SearchOption option)
- {
- _root = root;
- _patterns = patterns;
- _option = option;
- }
- public IEnumerator<FileSystemInfo> GetEnumerator()
- {
- if (_root == null || !_root.Exists) yield break;
- IEnumerable<FileSystemInfo> matches = new List<FileSystemInfo>();
- 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}'.",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);
人们可以自由使用它,如果他们觉得有用.