2012-10-29 6 views
9

Ich hatte in letzter Zeit eine Notwendigkeit, ein gesamtes Dateisystem auf der Suche nach bestimmten Dateitypen für Auditingzwecke aufzuzählen. Dies hat dazu geführt, dass ich aufgrund von eingeschränkten Berechtigungen für das zu scannende Dateisystem mehrere Ausnahmen habe. Unter ihnen waren die häufigsten UnauthorizedAccessException und sehr zu meinem Leidwesen, PathTooLongException.DirectoryInfo.EnumerateFiles (...) verursacht UnauthorizedAccessException (und andere Ausnahmen)

Dies wäre normalerweise kein Problem, außer dass sie das IEnumerable ungültig machen, sodass ich den Scanvorgang nicht abschließen kann.

Antwort

14

Um dieses Problem zu lösen, habe ich einen Ersatz-Dateisystem-Enumerator erstellt. Obwohl es vielleicht nicht perfekt ist, führt es ziemlich schnell aus und fängt die zwei Ausnahmen ein, auf die ich gestoßen bin. Es findet alle Verzeichnisse oder Dateien, die dem Suchmuster entsprechen.

// 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(); 
    } 
} 

Die Verwendung ist ziemlich einfach.

Leute sind frei, es zu benutzen, wenn sie es nützlich finden.

+0

"Menschen sind frei, es zu benutzen, wenn sie es nützlich finden." : Das ist nicht ganz so wahr. Ihre Ausübung unter CC BY SA 3, (kreative Commons), die es heikel macht, als eine Tatsache zu verwenden. Sie könnten explizit "public domain" (copyleft) oder zlib license (schwächste Copyright-Lizenz) angeben, in Ihrem Code-Snippet in einem Kommentar. Vielen Dank. –

+1

Ich behaupte, dass der Code in der obigen Antwort vom 14. Juli 2015 Public Domain mit allen Rechten und Privilegien ist, die gewährt. –

+1

Ich habe festgestellt, dass ich 'System.IO.IOException' für Situationen erfassen musste, in denen ich ein Netzlaufwerk mit einem Simlink-Verzeichnis remote-zu-lokal mit solchen Simlink-Erweiterungsregeln [auf der aktuellen Maschine deaktiviert] (http: // blogs.msdn.com/b/junfeng/archive/2012/05/07/the-symbolic-link-cannot-be-followed-because-its-type-is-disabled.aspx). Ich habe deine Antwort entsprechend angepasst. Es rekursiert auch unendlich, wenn es auf einen Simlink trifft, der auf einen Vorfahrenordner zeigt; in meinem Fall ignorierte ich einfach Verzeichnisse mit Attributen von 'FileAttributes.ReparsePoint', aber das ist wahrscheinlich nicht elegant genug für eine allgemeine Antwort. – RJFalconer

Verwandte Themen