2016-04-20 6 views
1

Ich bin eine Windows-Anwendung in Visual Studio 2012 in C# und. NET 4.0 erstellen.Mehrere Wildcard-Verzeichnis/Dateisuche für beliebige Verzeichnisstruktur in C# .net

Eine der Funktionen des Programms besteht darin, nach allen Dateien zu suchen, die bestimmte Suchkriterien erfüllen, die normalerweise (aber nicht immer) Platzhalter enthalten.

Die Suchkriterien sind zur Laufzeit unbekannt. Es wird aus einer Excel-Tabelle importiert.

Mögliche Suchkriterien können, gehören die folgenden:

  1. Exact Weg
    • "C: \ temp \ directory1 \ directory2 \ somefile.txt"
  2. Path, mit Wildcards in der Dateiname:
    • "C: \ temp \ Verzeichnis1 \ Verzeichnis2 *. *"
  3. Dateiname mit Platzhalter im Pfad:
    • "C: \ temp * \ * Verzeichnis \ somefile.txt"
  4. Dateinamen und Pfad mit Platzhalter:
    • " C: \ temp \ * \ * \ *. * "
  5. Alle oben genannten mit beliebiger Verzeichnisstruktur:
    • "C: \ temp \ dir * 1 \ dir * \ anotherdir \ * \ * eine andere \ file * .txt"
    • "C: \ te * \ * \ somefile.txt"
    • „C :.

      IEnumerable<string> matchingFilePaths = System.IO.Directory.EnumerateFiles(@"C:\", selectedItemPath[0], System.IO.SearchOption.AllDirectories); 
      

      jedoch diese nur: \ temp \ * tory1 \ dire * 2 \ * \ * \ * \ * \ * *“

ich habe Directory.EnumerateFiles zu verwenden versucht arbeitet mit Fall 2 oben. Der Versuch, Directory.EnumerateFiles mit Platzhaltern in den Ordnernamen zu verwenden, verursacht eine "Illegal Character" -Ausnahme.

Ich hoffe, es gibt ein One-Liner in .net kann ich verwenden, um diese Datei suchen zu tun. Die Anzahl der Platzhalter und die Tiefe der Verzeichnisstruktur ist zur Laufzeit unbekannt, und es ist denkbar, dass die Suche möglicherweise hundert Ordner tief gehen muss, wobei jeder Ordner eine unbekannte Anzahl von Platzhaltern enthält. (Dies ist der Kern des Problems). Der Versuch, eine wahnsinnige Anzahl verschachtelter For-Schleifen zu vermeiden.

Ich lese die Lösungen here, aber das scheint nicht für eine beliebige Ordnerstruktur zu arbeiten.

+0

Ich fürchte, .net hat API für Ihre Anforderung. Sie müssen es selbst schreiben. – RajN

+0

Es ist klar, dass die Frage, die Sie ansprechen, einen Platz hat, um Sie zu beginnen, und wenn Sie das selbst tun wollten, das das als eine Referenz verwendend, konnten Sie zweifellos. Fordern Sie uns auf, diese Arbeit ohne besondere Anstrengung für Sie zu erledigen? – caesay

Antwort

1

Da Sie Ihre eigene Frage bereits beantwortet haben, dachte ich mir, ich würde meinen Versuch dort für alle anderen posten, die dies finden könnten und keine Powershell verwenden möchten. Es ist alles faul geladen, so dass seine Leistung optimal ist, wenn Sie ein großes Dateisystem haben und viele Dateien abgleichen.

Probe Verbrauch:

string pattern = @"C:\Users\*\Source\Repos\*\*.cs"; 
foreach (var st in GetAllMatchingPaths(pattern)) 
    Console.WriteLine(st); 

Lösung:

public static IEnumerable<string> GetAllMatchingPaths(string pattern) 
{ 
    char separator = Path.DirectorySeparatorChar; 
    string[] parts = pattern.Split(separator); 

    if (parts[0].Contains('*') || parts[0].Contains('?')) 
     throw new ArgumentException("path root must not have a wildcard", nameof(parts)); 

    return GetAllMatchingPathsInternal(String.Join(separator.ToString(), parts.Skip(1)), parts[0]); 
} 

private static IEnumerable<string> GetAllMatchingPathsInternal(string pattern, string root) 
{ 
    char separator = Path.DirectorySeparatorChar; 
    string[] parts = pattern.Split(separator); 

    for (int i = 0; i < parts.Length; i++) 
    { 
     // if this part of the path is a wildcard that needs expanding 
     if (parts[i].Contains('*') || parts[i].Contains('?')) 
     { 
      // create an absolute path up to the current wildcard and check if it exists 
      var combined = root + separator + String.Join(separator.ToString(), parts.Take(i)); 
      if (!Directory.Exists(combined)) 
       return new string[0]; 

      if (i == parts.Length - 1) // if this is the end of the path (a file name) 
      { 
       return Directory.EnumerateFiles(combined, parts[i], SearchOption.TopDirectoryOnly); 
      } 
      else // if this is in the middle of the path (a directory name) 
      { 
       var directories = Directory.EnumerateDirectories(combined, parts[i], SearchOption.TopDirectoryOnly); 
       var paths = directories.SelectMany(dir => 
        GetAllMatchingPathsInternal(String.Join(separator.ToString(), parts.Skip(i + 1)), dir)); 
       return paths; 
      } 
     } 
    } 

    // if pattern ends in an absolute path with no wildcards in the filename 
    var absolute = root + separator + String.Join(separator.ToString(), parts); 
    if (File.Exists(absolute)) 
     return new[] { absolute }; 

    return new string[0]; 
} 

PS: Es wird nicht Verzeichnisse entsprechen, werden nur Dateien, aber man konnte leicht modifizieren, dass, falls gewünscht.

+0

Danke für die Lösung! Ich hatte gehofft, etwas Kompliziertes zu vermeiden, und ich denke, dass meine PowerShell-Methode funktionieren sollte, aber wenn ich eine Situation finde, wo es nicht geht, werde ich Ihre Lösung verwenden. –

1

Nach mehr Suche ergab sich eine sehr einfache Lösung.Ich kann die Windows Power Get-ChildItem Befehle verwenden:

using System.Management.Automation; 

PowerShell ps = PowerShell.Create(); 
ps.AddCommand("Get-ChildItem"); 
ps.AddArgument(selectedItemPath[0]); 
foreach (var result in ps.Invoke()) 
{ 
    //display the results in a textbox 
} 

Dies ermöglicht eine verschachtelten for Schleifen zu vermeiden.