爲了解決這個問題,我創建了一個替代文件系統枚舉器。雖然它可能不完美,但它表現相當快,並陷入我遇到的兩個例外。它會查找與傳遞給它的搜索模式相匹配的任何目錄或文件。
// 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}'.", _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);
人們可以自由使用它,如果他們覺得有用。
「人們可以自由使用它,如果他們覺得有用。」 :這不太真實。你在CC BY SA 3中發揮作用,(創意共同體),事實上它使用起來很微妙。您可以在評論中的代碼段中明確聲明「公有領域」(copyleft)或zlib許可(最弱版權許可)。謝謝。 –
我聲稱上述截至2015年7月14日的答案中的代碼是具有授予的所有權利和特權的公有領域。 –
我發現我需要趕上'System.IO.IOException'的情況下,我行走一個網絡驅動器,有一個遠程到本地的simlink目錄,這種simlink擴展規則[在當前機器上禁用](http:// blogs.msdn.com/b/junfeng/archive/2012/05/07/the-symbolic-link-cannot-be-followed-because-its-type-is-disabled.aspx)。我相應地調整了你的答案。如果遇到指向祖先文件夾的simlink,它也會無限遞歸;在我的情況下,我只是忽略了具有FileAttributes.ReparsePoint屬性的dirs,但是這對於一般的答案可能不夠優雅 – RJFalconer