2009-07-31 13 views
17

Hier ist das Problem, ich habe eine Reihe von Verzeichnissen wieNormalisieren Verzeichnisnamen in C#

S: \ HALLO \ HALLO
S: \ Hello2 \ HALLO \ helloagain

Auf der Datei System zeigt es diese Verzeichnisse als

S: \ Hallo \ Hallo
S: \ hello2 \ Hallo \ helloagain

Gibt es irgendeine Funktion in C#, die mir gibt, wie der Dateisystem-Name eines Verzeichnisses mit dem richtigen Gehäuse ist?

+0

Es gibt keine Funktion, um dies zu tun, und versuchen, Zeichenfolgen wie "HelloAgain" zu "HalloAgain" zu normalisieren wird ein Problem sein, da auch Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase ("HLloAgain") "Helloagain. –

+0

@Agent, DirectoryInfo. GetDirectories() gibt Ordner im Dateisystem zurück – Kevin

+1

Akzeptiert, wow, ich hatte keine Ahnung, dass neue Antworten hier waren Danke an Iceman und Bertu für die Hilfe bei der Lösung – Tom

Antwort

8

string FileSystemCasing = new System.IO.DirectoryInfo("H:\...").FullName;

EDIT:

Wie Eismann erwähnt, der Fullname gibt die richtigen Gehäuse nur, wenn die Directory (oder allgemein das Filesystem) von einem Aufruf an dem GetDirectories kommt (oder GetFileSystemInfos) -Methode.

Jetzt poste ich eine getestete und leistungsoptimierte Lösung. Es funktioniert gut sowohl auf Verzeichnis- als auch auf Dateipfaden und weist eine gewisse Fehlertoleranz für die Eingabezeichenfolge auf. Es ist optimiert für "Umwandlung" von einzelnen Pfaden (nicht das gesamte Dateisystem) und schneller als den gesamten Dateisystembaum. Natürlich, wenn Sie den gesamten Dateisystembaum renormieren haben, können Sie iceman-Lösung bevorzugen, aber ich auf 10000 Iterationen auf Pfade mit mittlerem Niveau der Tiefe getestet, und es dauert nur wenige Sekunden;)

private string GetFileSystemCasing(string path) 
    { 
     if (Path.IsPathRooted(path)) 
     { 
      path = path.TrimEnd(Path.DirectorySeparatorChar); // if you type c:\foo\ instead of c:\foo 
      try 
      { 
       string name = Path.GetFileName(path); 
       if (name == "") return path.ToUpper() + Path.DirectorySeparatorChar; // root reached 

       string parent = Path.GetDirectoryName(path); // retrieving parent of element to be corrected 

       parent = GetFileSystemCasing(parent); //to get correct casing on the entire string, and not only on the last element 

       DirectoryInfo diParent = new DirectoryInfo(parent); 
       FileSystemInfo[] fsiChildren = diParent.GetFileSystemInfos(name); 
       FileSystemInfo fsiChild = fsiChildren.First(); 
       return fsiChild.FullName; // coming from GetFileSystemImfos() this has the correct case 
      } 
      catch (Exception ex) { Trace.TraceError(ex.Message); throw new ArgumentException("Invalid path"); } 
      return ""; 
     } 
     else throw new ArgumentException("Absolute path needed, not relative"); 
    } 
+1

Das funktioniert nicht wirklich. Es gibt den gleichen Fall zurück, in dem Sie den DirectoryInfo-Konstruktor übergeben und den tatsächlichen Fall ignoriert haben, der im Dateisystem gespeichert ist, aber es ist der Dateisystemfall, den er haben möchte. – Kevin

+0

Sie haben Recht. Ich habe bearbeitet, um ein vollständiges Arbeitsbeispiel vorzulegen. – BertuPG

+1

Ich entschuldige mich. Dein erster Kommentar schien eher feindselig zu sein, als du wahrscheinlich meintest, und ich hätte ihn loslassen sollen, anstatt einen Streit anzufangen. Ich sollte wirklich aus dem Internet bleiben, wenn ich mürrisch bin. Es ist eine wirklich gute Idee, den Weg zu teilen und den Fall eines jeden Stücks zu bekommen, und es macht den Unterschied zwischen schmerzhaft langsam und brauchbar. Ich kann deine Antwort nicht verbessern, wenn du sie nicht redigierst, aber das hat mich nicht davon abgehalten, einige deiner anderen Antworten zu verbessern. Entschuldige, dass ich ein Idiot bin - ich schulde dir einen Drink, wenn du jemals in Denver bist. – Kevin

-1

Dies sollte es tun:

System.IO.Directory.GetFiles("..."); 
+0

Ich sehe nicht, was Sie sagen/implizieren wollen Das wirft "Konnte nicht finden ein Teil des Weges "..." ". – binki

+0

@binki Das ist nur geläufiges Englisch. Ersetzen Sie "..." für den Ordner, den Sie wirklich suchen wollten. –

+0

Dann vermute ich, dass Sie die Frage falsch verstanden haben. Wenn ich 'Directory.GetFiles (@" \ USERS \ OHNOB \ HELLO ")' mache, bekomme ich '{" \ USERS \ OHNOB \ HELLO \ Hi "}' anstelle von '{" \ Users \ ohnob \ hallo \ Hi " } '. Ich bin mir ziemlich sicher, dass die Frage ist, wie man das Letztere bekommt. – binki

-3

 
     static void Main(string[] args) 
     { 
     string[] paths = new string[] { "S:\hello\Hi", "S:\hello2\Hi\helloAgain" }; 
     foreach(string aPath in paths) 
     { 
      string normalizedPath = NormalizePath(aPath); 
      Console.WriteLine("Previous: '{0}', Normalized: '{1}'", aPath, normalizedPath); 
     } 
     Console.Write("\n\n\nPress any key..."); 
     Console.Read(); 
     }

public static string NormalizePath(string path) 
    { 
    StringBuilder sb = new StringBuilder(path); 
    string[] paths = path.Split('\\'); 
    foreach(string folderName in paths) 
    { 
     string normalizedFolderName = ToProperCase(folderName); 
     sb.Replace(folderName, normalizedFolderName); 
    } 
    return sb.ToString(); 
    } 

    /// <summary> 
    /// Converts a string to first character upper and rest lower (Camel Case). 
    /// </summary> 
    /// <param name="stringValue"></param> 
    /// <returns></returns> 
    public static string ToProperCase(string stringValue) 
    { 
    if(string.IsNullOrEmpty(stringValue)) 
     return stringValue; 

    return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(stringValue.ToLower()); 
    } 

+2

Er fragt nach dem Gehäuse, das auf dem Dateisystem gespeichert ist, nicht unbedingt TitleCasing. – Kevin

4

Hier ist eine grundlegende und relativ schnelle Lösung, halte unten für einige Kommentare zu lesen:

private static string GetCase(string path) 
{  
    DirectoryInfo dir = new DirectoryInfo(path); 
    if (dir.Exists) 
    { 
    string[] folders = dir.FullName.Split(Path.DirectorySeparatorChar); 
    dir = dir.Root; 

    foreach (var f in folders.Skip(1)) 
    {   
     dir = dir.GetDirectories(f).First(); 
    } 

    return dir.FullName; 
    } 
    else 
    { 
    return path; 
    } 
} 

Die Grundidee ist, dass das Erhalten von Unterverzeichnissen von einem DirectoryInfo-Objekt Sie bekommen wird der richtige Fall, also müssen wir nur den Verzeichnisnamen aufteilen und von der Wurzel zum Zielverzeichnis gehen, um bei jedem Schritt den richtigen Fall zu erhalten.

Meine erste Antwort verließ sich darauf, das Gehäuse für jeden Ordner auf dem Laufwerk zu bekommen, und es funktionierte, war aber langsam. Ich kam zu einer leichten Verbesserung, die die Ergebnisse speicherte, aber für den täglichen Gebrauch war es immer noch zu langsam. Sie können den Bearbeitungsverlauf für diesen Kommentar sehen, wenn Sie dies für jedes Objekt auf dem Laufwerk tun müssen, und selbst dann gibt es wahrscheinlich Möglichkeiten, diesen Code zu beschleunigen. Es war "Hier ist, wie Sie es tun könnten" und nicht "hier ist ein guter Weg, es zu tun."

Bertu, in seiner Antwort, kam auf die Idee des Teilens den Weg in seine Komponenten und bekommen das Gehäuse Stück für Stück nach oben, die in einer großen Geschwindigkeitserhöhung führt, da Sie nicht mehr sind alles Überprüfung als in meiner ursprünglichen Antwort. Bertu verallgemeinerte auch seine Lösung, sowohl Dateien als auch Verzeichnisse zu erstellen. In meinen Tests läuft der oben genannte Code (der Bertus "spaltet den Pfad und tu es nach Stücken" Idee aber nähert es iterativ statt rekursiv) in etwa der Hälfte der Zeit von Bertus Code. Ich bin mir nicht sicher, ob das daran liegt, dass seine Methode auch Dateien verarbeitet, weil seine Verwendung der Rekursion zusätzlichen Overhead verursacht, oder weil er in jeder Iteration Path.GetFileName(path) und Path.GetDirectoryName(path) aufruft. Abhängig von Ihren genauen Bedürfnissen, wird eine Kombination aus Ihrer Antwort und meiner wahrscheinlich Ihr Problem lösen, wie es in C# möglich ist.

In diesem Sinne sollte ich erwähnen, dass es gibt some limitations zu .Net Dateiname Handhabung, und da dies in.Net erfordert eine Menge von DirectoryInfo Objekte machen, möchten Sie möglicherweise nicht verwalteten Code berücksichtigen, wenn dies Ihr Engpass ist.

+0

das funktioniert, aber es ist SCHLECHT langsam, da es einen vollständigen System-Scan für Such-Verzeichnis und ich habe über 100 Verzeichnisse zu normalisieren – Tom

+0

@Tom, siehe mein Update. Ich hätte anfangs über mehrere Verzeichnisse nachdenken sollen. – Kevin

+0

@Tom: siehe bearbeiten in meinem Post! ;) – BertuPG