C# · 12月 22, 2021

c# – DirectoryInfo.EnumerateFiles(…)导致UnauthorizedAccessException(和其他异常)

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

这些通常不会是一个问题,除了它们使IEnumerable无效,阻止我无法完成扫描.

解决方法 为了解决这个问题,我创建了一个替换文件系统枚举器.虽然它可能不完美,但它执行得相当快,并且陷入了我遇到的两个例外.它会找到与传递给它的搜索模式匹配的任何目录或文件. // This code is public domainusing 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 domainvar root = new DirectoryInfo(@”c:\wherever”);var searchPattern = @”*.txt”;var searchOption = SearchOption.AllDirectories;var enumerable = new FileSystemEnumerable(root,searchPattern,searchOption);

人们可以自由使用它,如果他们觉得有用.