做得好,这里提供一个扩展代码,返回FileSystemInfo而不是字符串路径。有一些行上的小修改,比如添加SearchOption(就像本地 .net 一样),以及在获取初始目录时进行错误捕获,以防根文件夹被拒绝访问。再次感谢您发布原始帖子!
public class SafeFileEnumerator : IEnumerable<FileSystemInfo>
{
private DirectoryInfo root;
private string pattern;
private SearchOption searchOption;
private IList<Exception> errors;
public SafeFileEnumerator(string root, string pattern, SearchOption option)
: this(new DirectoryInfo(root), pattern, option)
{}
public SafeFileEnumerator(DirectoryInfo root, string pattern, SearchOption option)
: this(root, pattern, option, new List<Exception>())
{}
private SafeFileEnumerator(DirectoryInfo root, string pattern, SearchOption option, IList<Exception> errors)
{
if (root == null || !root.Exists)
{
throw new ArgumentException("Root directory is not set or does not exist.", "root");
}
this.root = root;
this.searchOption = option;
this.pattern = String.IsNullOrEmpty(pattern)
? "*"
: pattern;
this.errors = errors;
}
public Exception[] Errors
{
get
{
return errors.ToArray();
}
}
private class Enumerator : IEnumerator<FileSystemInfo>
{
private IEnumerator<FileSystemInfo> fileEnumerator;
private IEnumerator<DirectoryInfo> directoryEnumerator;
private DirectoryInfo root;
private string pattern;
private SearchOption searchOption;
private IList<Exception> errors;
public Enumerator(DirectoryInfo root, string pattern, SearchOption option, IList<Exception> errors)
{
this.root = root;
this.pattern = pattern;
this.errors = errors;
this.searchOption = option;
Reset();
}
public FileSystemInfo Current
{
get
{
return fileEnumerator.Current as FileSystemInfo;
}
}
object System.Collections.IEnumerator.Current
{
get { return Current; }
}
public void Dispose()
{
Dispose(true, true);
}
private void Dispose(bool file, bool dir)
{
if (file)
{
if (fileEnumerator != null)
fileEnumerator.Dispose();
fileEnumerator = null;
}
if (dir)
{
if (directoryEnumerator != null)
directoryEnumerator.Dispose();
directoryEnumerator = null;
}
}
public bool MoveNext()
{
if ((fileEnumerator != null) && (fileEnumerator.MoveNext()))
return true;
if (searchOption == SearchOption.TopDirectoryOnly) { return false; }
while ((directoryEnumerator != null) && (directoryEnumerator.MoveNext()))
{
Dispose(true, false);
try
{
fileEnumerator = new SafeFileEnumerator(
directoryEnumerator.Current,
pattern,
SearchOption.AllDirectories,
errors
).GetEnumerator();
}
catch (Exception ex)
{
errors.Add(ex);
continue;
}
if (fileEnumerator.MoveNext())
return true;
}
Dispose(true, true);
return false;
}
public void Reset()
{
Dispose(true,true);
if (root != null)
{
try
{
fileEnumerator = root.GetFileSystemInfos(pattern, SearchOption.TopDirectoryOnly).AsEnumerable<FileSystemInfo>().GetEnumerator();
}
catch (Exception ex)
{
errors.Add(ex);
fileEnumerator = null;
}
try
{
directoryEnumerator = root.GetDirectories(pattern, SearchOption.TopDirectoryOnly).AsEnumerable<DirectoryInfo>().GetEnumerator();
}
catch (Exception ex)
{
errors.Add(ex);
directoryEnumerator = null;
}
}
}
}
public IEnumerator<FileSystemInfo> GetEnumerator()
{
return new Enumerator(root, pattern, searchOption, errors);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
.Parallel()
唯一能做的就是将new Foobar()
操作线程化(这可能需要时间;毕竟它必须解析一个巨大的字符串)。对吗?我想知道为每个new Foobar()
启动新线程的成本是否比在单个线程中串行创建new Foobar()
对象更昂贵。 - user979672