2009-07-31 11 views
17

Ecco il problema, ho un sacco di directory comeNormalizzare nomi delle directory in C#

S: \ CIAO \ HI
S: \ Hello2 \ HI \ HElloAgain

Nel file sistema mostra queste directory come

S: \ ciao \ Hi
S: \ Hello2 \ Hi \ helloAgain

C'è qualche funzione in C# che mi fornirà il nome del file system di una directory con l'involucro corretto?

+0

C'è nessuna funzione per fare questo, e cercando di normalizzare le stringhe come "HElloAgain" a "helloAgain" sarà un problema in quanto anche Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase ("HElloAgain") restituirà "Helloagain. –

+0

@Agent, DirectoryInfo. GetDirectories() restituisce le cartelle nel caso del file system. – Kevin

+1

accettate, wow non avevo idea che nuove risposte erano qui. Grazie a entrambi Iceman e Bertu per aiutare a risolvere questo. – Tom

risposta

8

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

EDIT:

Come iceman sottolineato, il FullName restituisce l'involucro corretta solo se la DirectoryInfo (o in generale la FileSystemInfo) proviene da una chiamata al GetDirectories (o GetFileSystemInfos) metodo.

Ora sto postando una soluzione testata e prestazioni ottimizzate. Funziona bene su directory e percorsi di file e presenta una tolleranza di errore sulla stringa di input. È ottimizzato per "conversione" di singoli percorsi (non dell'intero file system) e più veloce di ottenere l'intero albero del file system. Naturalmente, se si deve rinormalizzare l'intero albero del file system, si può preferire la soluzione di iceman, ma ho testato su 10000 iterazioni su percorsi con livello medio di profondità, e richiede solo pochi secondi;)

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

Questo in realtà non funziona. Restituisce lo stesso caso che si passa al costruttore di DirectoryInfo e ignora il caso reale memorizzato nel filesystem, ma è il caso del filesystem che vuole. – Kevin

+0

Hai ragione. Ho modificato per presentare un esempio operativo completo. – BertuPG

+1

Mi scuso. Il tuo primo commento è sembrato più ostile di quanto probabilmente intendessi, e avrei dovuto lasciarlo andare invece di iniziare una discussione. Dovrei davvero stare fuori da Internet quando sono scontroso. Dividere il percorso e ottenere la cassa di ogni pezzo è una buona idea, e fa la differenza tra dolorosamente lento e utilizzabile. Non posso revocare la tua risposta a meno che tu non la modifichi, ma ciò non mi ha impedito di svalutare alcune delle tue altre risposte. Scusa per essere un idiota: ti devo un drink se sei a Denver. – Kevin

-1

Questo dovrebbe farlo:

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

non vedo quello che stai cercando di dire/implicare . Quello lancia "Impossibile trovare una parte del percorso "..." ". – binki

+0

@binki È solo inglese comune. Sostituisci "..." per qualunque cartella desideri veramente cercare. –

+0

Quindi sospetto che abbiate frainteso la domanda. Quando faccio 'Directory.GetFiles (@" \ USERS \ OHNOB \ HELLO ")', ottengo '{" \ USERS \ OHNOB \ HELLO \ Hi "}' invece di '{" \ Users \ ohnob \ ciao \ Hi " } '. Sono abbastanza certo che la domanda è come chiedere il secondo. – 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

Chiede l'involucro come memorizzato nel file system, non necessariamente TitleCasing. – Kevin

4

Ecco una soluzione di base e relativamente veloce, continuate a leggere qui sotto per qualche commento:

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; 
    } 
} 

L'idea di base è che ottenere sottodirectory da un oggetto DirectoryInfo ti porterà il caso corretto, quindi abbiamo solo bisogno di dividere il nome della directory e passare dalla radice alla directory di destinazione, ottenendo il caso corretto ad ogni passaggio.

La mia risposta iniziale si è basata sull'ottenere l'involucro per ogni cartella sull'unità e ha funzionato, ma era lento. Ho trovato un leggero miglioramento che memorizzava i risultati, ma era ancora troppo lento per l'uso quotidiano. Puoi vedere la cronologia delle modifiche per questo commento se hai bisogno di fare questo per ogni cosa sul disco, e anche allora ci sono probabilmente dei modi per velocizzare quel codice. Era "ecco come potresti farlo" e non "ecco un ottimo modo per farlo".

Bertu, nella sua risposta, si avvicinò con l'idea di dividere il percorso nelle sue componenti e ottenere il pezzo per pezzo dell'involucro, che si traduce dal momento che non sei più il controllo tutto come in un enorme aumento velocità nella mia risposta originale Bertu ha anche generalizzato la sua soluzione per fare file e directory. Nei miei test, il codice postato sopra (che utilizza l'idea di Bertu di "dividere il percorso e farlo per pezzo" ma si avvicina iterativamente anziché ricorsivamente) viene eseguito in circa la metà del tempo del codice di Bertu. Non sono sicuro che ciò sia dovuto al fatto che il suo metodo gestisce anche i file, perché il suo uso della ricorsione introduce un sovraccarico aggiuntivo, o perché finisce per chiamare Path.GetFileName(path) e Path.GetDirectoryName(path) in ogni iterazione. A seconda delle tue esatte esigenze, una combinazione della sua risposta e mia probabilmente risolverà il tuo problema oltre che in C#.

In tale nota, dovrei ricordare che ci sono some limitations alla gestione dei nomi di file .Net, e dal momento che farlo in .Net richiede di creare molti oggetti DirectoryInfo, si potrebbe voler prendere in considerazione il codice non gestito se questo è il collo di bottiglia.

+0

questo funziona, ma è dolorosamente lenta dal momento che una scansione completa del sistema per la directory di ricerca e ho più di 100 directory per normalizzare – Tom

+0

@ Tom, vedere il mio aggiornamento. Avrei dovuto pensare a più directory inizialmente. – Kevin

+0

@Tom: vedi modifica nel mio post! ;) – BertuPG

Problemi correlati