Per risolvere questo problema, ho creato un enumeratore file system sostitutivo. Anche se potrebbe non essere perfetto, funziona abbastanza velocemente e intrappola le due eccezioni in cui mi sono imbattuto. Troverà qualsiasi directory o file che corrispondono al modello di ricerca passato ad esso.
// 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();
}
}
L'utilizzo è abbastanza semplice.
//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);
Le persone sono libere di usarlo se lo trovano utile.
fonte
2012-10-29 21:37:52
"Le persone sono libere di usarlo se lo trovano utile." : non è proprio vero. il tuo esercizio in CC BY SA 3, (commons creative) che lo rende delicato da usare come dato di fatto. È possibile indicare in modo esplicito la licenza "dominio pubblico" (copyleft) o zlib (la più debole licenza di copyright) nel frammento di codice in un commento. Grazie. –
Asserisco che il codice nella risposta sopra al 14 luglio 2015 è di dominio pubblico con tutti i diritti e privilegi che concede. –
Ho trovato che avevo bisogno di prendere 'System.IO.IOException' per le situazioni in cui sto camminando su un'unità di rete che ha una directory simlink da remoto a locale con tali regole di espansione simlink [disabilitate sulla macchina corrente] (http: // blogs.msdn.com/b/junfeng/archive/2012/05/07/the-symbolic-link-cannot-be-followed-because-its-type-is-disabled.aspx). Ho modificato la tua risposta di conseguenza. Ricorre anche all'infinito se incontra un collegamento simbolico che punta a una cartella degli antenati; nel mio caso ho semplicemente ignorato dirs con attributi di 'FileAttributes.ReparsePoint', ma probabilmente non è abbastanza elegante per una risposta generale – RJFalconer