Dot-Net
Directory.EnumerateFiles => UnauthorizedAccessException
.NET 4.0 中有一個很好的新方法,可以通過枚舉以流的方式獲取目錄中的文件。
這裡的問題是,如果希望枚舉所有文件,可能事先不知道哪些文件或文件夾受訪問保護,並可能引發 UnauthorizedAccessException。
要重現,只需執行以下片段:
foreach (var file in Directory.EnumerateFiles(@"c:\", "*", SearchOption.AllDirectories)) { // whatever }在此 .NET 方法存在之前,可以通過在字元串數組返回方法上實現遞歸迭代器來實現大致相同的效果。但它並不像新的 .NET 方法那麼懶惰。
那麼該怎麼辦?使用此方法時,UnauthorizedAccessException 是否可以被抑製或成為現實?
在我看來,該方法應該具有接受處理任何異常的動作的重載。
上述答案的問題是不處理子目錄中的異常。這將是處理這些異常的更好方法,因此您可以從所有子目錄中獲取所有文件,除了那些拋出訪問異常的文件:
/// <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; }
我無法讓上面的工作,但這是我的實現,我已經在“Win7”框上的 c:\users 上對其進行了測試,因為如果有所有這些“討厭的”目錄:
SafeWalk.EnumerateFiles(@"C:\users", "*.jpg", SearchOption.AllDirectories).Take(10)班級:
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>(); } } }