2009-07-31 17 views
17

aquí está el problema, tengo un montón de directorios comoNormalizar nombres de directorio en C#

S: \ HOLA \ HI
S: \ Hello2 \ HI \ HElloAgain

En el archivo sistema que muestra estos directorios como

S: \ hola \ Hola
S: \ hello2 \ Hola \ helloAgain

¿Hay alguna función en C# que me proporcione el nombre del sistema de archivos de un directorio con la carcasa adecuada?

+0

Hay no hay función para hacer eso, y tratar de normalizar cadenas como "HElloAgain" a "helloAgain" será un problema ya que incluso Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase ("HElloAgain") devolvería "Helloagain. –

+0

@Agent, DirectoryInfo. GetDirectories() devuelve carpetas en el caso del sistema de archivos. – Kevin

+1

Aceptado, wow No tenía idea de que hubiera nuevas respuestas aquí Gracias a Iceman y Bertu por ayudar a resolver esto. – Tom

Respuesta

8

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

EDIT:

Como iceman señaló, el FullName devuelve la carcasa correcta sólo si la DirectoryInfo (o en general el FileSystemInfo) proviene de una llamada al método GetDirectories (o GetFileSystemInfos).

Ahora estoy publicando una solución probada y optimizada para el rendimiento. Funciona bien tanto en el directorio como en las rutas de archivos, y tiene cierta tolerancia a fallas en la cadena de entrada. Está optimizado para la "conversión" de rutas únicas (no todo el sistema de archivos), y más rápido que obtener el árbol completo del sistema de archivos. Por supuesto, si usted tiene que renormalizar todo el árbol del sistema de archivos, puede preferir la solución de hombre de hielo, pero probado en 10000 iteraciones en caminos con nivel medio de profundidad, y se tarda solo unos segundos;)

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

Esto en realidad no funciona. Devuelve el mismo caso al pasar al constructor DirectoryInfo e ignora el caso real almacenado en el sistema de archivos, pero es el caso del sistema de archivos lo que él quiere. – Kevin

+0

Tienes razón. Modifiqué para enviar un ejemplo completo de trabajo. – BertuPG

+1

Me disculpo. Tu primer comentario me pareció más hostil de lo que probablemente querías decir, y debería haberlo dejado en lugar de comenzar una discusión. Realmente debería estar fuera de Internet cuando estoy de mal humor. Dividir el camino y obtener el caso de cada pieza es una muy buena idea, y hace la diferencia entre dolorosamente lento y usable. No puedo renunciar a su respuesta a menos que la edite, pero eso no me impidió votar algunas de sus otras respuestas. Perdón por ser un imbécil - Te debo una copa si alguna vez estás en Denver. – Kevin

-1

Esto debe hacerlo:

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

No veo lo que intentas decir/implicar . Eso arroja "No pude encontrar una parte de la ruta "..." ". – binki

+0

@binki Eso es solo inglés común. Sustituye "..." por la carpeta que realmente deseas buscar. –

+0

Entonces sospecho que ha malentendido la pregunta. Cuando hago 'Directory.GetFiles (@" \ USERS \ OHNOB \ HELLO ")', obtengo '{" \ USERS \ OHNOB \ HELLO \ Hi "}' en lugar de '{" \ Users \ ohnob \ hello \ Hi " } ' Estoy bastante seguro de que la pregunta es cómo obtener esto último. – 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

Está pidiendo la carcasa almacenada en el sistema de archivos, no necesariamente TitleCasing. – Kevin

4

Aquí es una solución básica y relativamente rápido, sigue leyendo a continuación para algunos comentarios:

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

La idea básica es que obtener subdirectorios de un objeto DirectoryInfo te ayudará el caso correcto, por lo que solo debemos dividir el nombre del directorio y caminar desde la raíz hasta el directorio de destino, obteniendo el caso adecuado en cada paso.

Mi respuesta inicial se basó en obtener la carcasa para cada carpeta en el disco, y funcionó pero fue lenta. Se me ocurrió una ligera mejora que almacenó los resultados, pero todavía era demasiado lenta para el uso diario. Puede ver el historial de edición de este comentario si necesita hacer esto para cada cosa en el disco, y aun así, probablemente haya formas de acelerar ese código. Era "así es como puedes hacerlo" y no "aquí hay una excelente manera de hacerlo".

Bertu, en su respuesta, se le ocurrió la idea de dividir la ruta en sus componentes y conseguir la pieza de carcasa por pieza, lo que se traduce en un aumento enorme velocidad ya que ya no está comprobando todo lo como en mi respuesta original. Bertu también generalizó su solución para hacer archivos y directorios. En mis pruebas, el código publicado arriba (que usa la idea de Bertu de "dividir el camino y hacerlo por piezas" pero se acerca iterativamente en lugar de recursivamente) se ejecuta en aproximadamente la mitad del tiempo del código de Bertu. No estoy seguro si eso se debe a que su método también maneja archivos, porque su uso de la recursión introduce una sobrecarga adicional, o porque termina llamando a Path.GetFileName(path) y Path.GetDirectoryName(path) en cada iteración. Dependiendo de sus necesidades exactas, es probable que una combinación de su respuesta y la mía resuelva su problema lo mejor posible en C#.

En ese sentido, debo mencionar que hay some limitations para el manejo de nombre de archivo .Net, y dado que hacer esto en .Net requiere hacer muchos objetos DirectoryInfo, es posible que desee considerar el código no administrado si este es su cuello de botella.

+0

esto funciona pero es DOLOROSAMENTE lento, ya que hace un escaneo completo del sistema para el directorio de búsqueda y tengo más de 100 directorios para normalizar – Tom

+0

@Tom, ver mi actualización. Debería haber pensado en varios directorios inicialmente. – Kevin

+0

@Tom: ver edición en MI publicación! ;) – BertuPG

Cuestiones relacionadas