2010-03-12 13 views
22

¿Hay alguna manera de verificar si una cadena para una ruta tiene caracteres inválidos, en .Net? Sé que podría iterar sobre cada personaje en Path.InvalidPathChars para ver si mi String contenía uno, pero preferiría una solución simple, tal vez más formal..Net: ¿Cómo verifico si hay caracteres ilegales en una ruta?

¿Hay uno?

he encontrado todavía consigo una excepción si sólo Cotejar Obtener

Actualizar:

que he encontrado GetInvalidPathChars no cubre todos los personajes ruta no válida. GetInvalidFileNameChars tiene 5 más, incluido '?', Que he encontrado. Voy a cambiar a eso, e informaré si también resulta inadecuado.

Actualización 2:

GetInvalidFileNameChars definitivamente no es lo que quiero. Contiene ':', que cualquier ruta absoluta va a contener ("C: \ whatever"). Creo que voy a tener que usar GetInvalidPathChars después de todo, y agregar '?' y cualquier otro personaje que me cause problemas a medida que surjan. Mejores soluciones bienvenidas.

+0

¿Por qué está etiquetado con "regex"? – incarnate

+0

No estoy seguro. Magnifico lo agregó. –

+0

Etiqueta regex eliminada. –

Respuesta

35

InvalidPathChars está en desuso. Utilice GetInvalidPathChars() en su lugar:

public static bool FilePathHasInvalidChars(string path) 
    { 

     return (!string.IsNullOrEmpty(path) && path.IndexOfAny(System.IO.Path.GetInvalidPathChars()) >= 0); 
    } 

Editar: Ligeramente más largo, pero se encarga de ruta vs archivo de caracteres no válidos en una función:

// WARNING: Not tested 
    public static bool FilePathHasInvalidChars(string path) 
    { 
     bool ret = false; 
     if(!string.IsNullOrEmpty(path)) 
     { 
      try 
      { 
       // Careful! 
       // Path.GetDirectoryName("C:\Directory\SubDirectory") 
       // returns "C:\Directory", which may not be what you want in 
       // this case. You may need to explicitly add a trailing \ 
       // if path is a directory and not a file path. As written, 
       // this function just assumes path is a file path. 
       string fileName = System.IO.Path.GetFileName(path); 
       string fileDirectory = System.IO.Path.GetDirectoryName(path); 

       // we don't need to do anything else, 
            // if we got here without throwing an 
            // exception, then the path does not 
            // contain invalid characters 
      } 
      catch (ArgumentException) 
      { 
            // Path functions will throw this 
            // if path contains invalid chars 
       ret = true; 
      } 
     } 
     return ret; 
    } 
+0

Estoy cansado ahora (3AM) pero creo que IndexOfAny devuelve -1 si no se encuentra ningún carácter inválido, por lo tanto, el resultado es verdadero si NO se encuentra dicho tipo de caracteres en el nombre de archivo o fileDirectory, exactamente lo contrario de lo que se quiere. Pero, más importante aún, ¿cómo resuelve esto "c: \ first \ second: third \ test.txt"? ¿Capturaría el segundo, ilegal ':'? – Avi

+0

Ver las ediciones de la publicación original. En cuanto a su otra pregunta, "C: \ first \ second: third \ test.txt" no contiene ningún carácter no válido para una ruta, ya que ":" es un carácter de ruta válido. Es cierto que la ruta es una ruta no válida, pero el propósito de la función no era validar las rutas adecuadas. Para eso, la mejor apuesta sería probar la cadena de ruta contra una expresión regular. También podría hacer: foreach (String s en path.Split ('\\')) {// prueba s para caracteres de archivo no válidos} pero esa implementación es un poco frágil ya que tiene que hacer una excepción para el "C:" –

+4

La segunda función no parece captar? o * caracteres. – snarf

3

Tenga cuidado cuando se basa en Path.GetInvalidFileNameChars, que puede no ser tan fiable como tu pensarías Observe el siguiente comentario en la documentación de MSDN en Path.GetInvalidFileNameChars:

La matriz devuelta por este método es no garantizados para contener el conjunto completo de caracteres que no son válidos en los nombres de archivos y directorios. El conjunto completo de caracteres no válidos puede variar según el sistema de archivos. Por ejemplo, en plataformas de escritorio basadas en Windows, los caracteres de ruta inválidos pueden incluir caracteres ASCII/Unicode del 1 al 31, así como comillas ("), menores que (<), mayores que (>), canalizaciones (|), retroceso (\ b), nulo (\ 0) y tabulación (\ t).

no es mejor con Path.GetInvalidPathChars método. contiene exactamente la misma observación.

+1

Los métodos 'GetInvalid * NameChars' no son útiles ni confiables. La validez/invalidez de la ruta está implícitamente ligada al sistema de archivos en el que se está ejecutando el código, y dado que System.IO. * No hace el rastreo del sistema de archivos, simplemente devuelve una matriz codificada, lo que no es válido en el sistema de archivos A puede ser completamente válido en sistema de archivos B. tl; dr: no confíe en estos métodos, haga los suyos. –

2

es probablemente demasiado tarde para ti, pero de mayo ayudar a alguien más. Me enfrenté al mismo problema y necesitaba encontrar una forma confiable de desinfectar un camino.

Esto es lo que terminé usando, en 3 pasos:

Paso 1: Limpieza personalizada.

public static string RemoveSpecialCharactersUsingCustomMethod(this string expression, bool removeSpecialLettersHavingASign = true) 
{ 
    var newCharacterWithSpace = " "; 
    var newCharacter = ""; 

    // Return carriage handling 
    // ASCII LINE-FEED character (LF), 
    expression = expression.Replace("\n", newCharacterWithSpace); 
    // ASCII CARRIAGE-RETURN character (CR) 
    expression = expression.Replace("\r", newCharacterWithSpace); 

    // less than : used to redirect input, allowed in Unix filenames, see Note 1 
    expression = expression.Replace(@"<", newCharacter); 
    // greater than : used to redirect output, allowed in Unix filenames, see Note 1 
    expression = expression.Replace(@">", newCharacter); 
    // colon: used to determine the mount point/drive on Windows; 
    // used to determine the virtual device or physical device such as a drive on AmigaOS, RT-11 and VMS; 
    // used as a pathname separator in classic Mac OS. Doubled after a name on VMS, 
    // indicates the DECnet nodename (equivalent to a NetBIOS (Windows networking) hostname preceded by "\\".). 
    // Colon is also used in Windows to separate an alternative data stream from the main file. 
    expression = expression.Replace(@":", newCharacter); 
    // quote : used to mark beginning and end of filenames containing spaces in Windows, see Note 1 
    expression = expression.Replace(@"""", newCharacter); 
    // slash : used as a path name component separator in Unix-like, Windows, and Amiga systems. 
    // (The MS-DOS command.com shell would consume it as a switch character, but Windows itself always accepts it as a separator.[16][vague]) 
    expression = expression.Replace(@"/", newCharacter); 
    // backslash : Also used as a path name component separator in MS-DOS, OS/2 and Windows (where there are few differences between slash and backslash); allowed in Unix filenames, see Note 1 
    expression = expression.Replace(@"\", newCharacter); 
    // vertical bar or pipe : designates software pipelining in Unix and Windows; allowed in Unix filenames, see Note 1 
    expression = expression.Replace(@"|", newCharacter); 
    // question mark : used as a wildcard in Unix, Windows and AmigaOS; marks a single character. Allowed in Unix filenames, see Note 1 
    expression = expression.Replace(@"?", newCharacter); 
    expression = expression.Replace(@"!", newCharacter); 
    // asterisk or star : used as a wildcard in Unix, MS-DOS, RT-11, VMS and Windows. Marks any sequence of characters 
    // (Unix, Windows, later versions of MS-DOS) or any sequence of characters in either the basename or extension 
    // (thus "*.*" in early versions of MS-DOS means "all files". Allowed in Unix filenames, see note 1 
    expression = expression.Replace(@"*", newCharacter); 
    // percent : used as a wildcard in RT-11; marks a single character. 
    expression = expression.Replace(@"%", newCharacter); 
    // period or dot : allowed but the last occurrence will be interpreted to be the extension separator in VMS, MS-DOS and Windows. 
    // In other OSes, usually considered as part of the filename, and more than one period (full stop) may be allowed. 
    // In Unix, a leading period means the file or folder is normally hidden. 
    expression = expression.Replace(@".", newCharacter); 
    // space : allowed (apart MS-DOS) but the space is also used as a parameter separator in command line applications. 
    // This can be solved by quoting, but typing quotes around the name every time is inconvenient. 
    //expression = expression.Replace(@"%", " "); 
    expression = expression.Replace(@" ", newCharacter); 

    if (removeSpecialLettersHavingASign) 
    { 
     // Because then issues to zip 
     // More at : http://www.thesauruslex.com/typo/eng/enghtml.htm 
     expression = expression.Replace(@"ê", "e"); 
     expression = expression.Replace(@"ë", "e"); 
     expression = expression.Replace(@"ï", "i"); 
     expression = expression.Replace(@"œ", "oe"); 
    } 

    return expression; 
} 

Paso 2: Compruebe los caracteres no válidos aún no se elimina.

A un paso de verificación adicional, utilizo el método Path.GetInvalidPathChars() publicado anteriormente para detectar cualquier posible carácter no válido aún no eliminado.

public static bool ContainsAnyInvalidCharacters(this string path) 
{ 
    return (!string.IsNullOrEmpty(path) && path.IndexOfAny(Path.GetInvalidPathChars()) >= 0); 
} 

Paso 3: Limpiar cualquier carácter especial detectados en el paso 2.

Y, por último, utilizo este método como último paso para limpiar cualquier cosa a la izquierda. (de How to remove illegal characters from path and filenames?):

public static string RemoveSpecialCharactersUsingFrameworkMethod(this string path) 
{ 
    return Path.GetInvalidFileNameChars().Aggregate(path, (current, c) => current.Replace(c.ToString(), string.Empty)); 
} 

que registra cualquier carácter no válido no se limpian en el primer paso. Elijo ir de esa manera para mejorar mi método personalizado tan pronto como se detecte una 'fuga'. No puedo confiar en el Path.GetInvalidFileNameChars() por la siguiente declaración de un reportado anteriormente (MSDN):

"La matriz devuelta por este método no está garantizado para contener la conjunto completo de caracteres que no son válidos en el archivo y el directorio nombres. "

puede que no sea la solución ideal, pero teniendo en cuenta el contexto de mi aplicación y el nivel de fiabilidad requerido, esta es la mejor solución que he encontrado.

1

que terminaron el endeudamiento y la combinación de unas pocas implementaciones .NET internas para llegar a un método performant:

/// <summary>Determines if the path contains invalid characters.</summary> 
/// <remarks>This method is intended to prevent ArgumentException's from being thrown when creating a new FileInfo on a file path with invalid characters.</remarks> 
/// <param name="filePath">File path.</param> 
/// <returns>True if file path contains invalid characters.</returns> 
private static bool ContainsInvalidPathCharacters(string filePath) 
{ 
    for (var i = 0; i < filePath.Length; i++) 
    { 
     int c = filePath[i]; 

     if (c == '\"' || c == '<' || c == '>' || c == '|' || c == '*' || c == '?' || c < 32) 
      return true; 
    } 

    return false; 
} 

luego lo usé como tal, sino también envolvió en un bloque try/catch para la seguridad :

if (!string.IsNullOrWhiteSpace(path) && !ContainsInvalidPathCharacters(path)) 
{ 
    FileInfo fileInfo = null; 

    try 
    { 
     fileInfo = new FileInfo(path); 
    } 
    catch (ArgumentException) 
    {    
    } 

    ... 
} 
Cuestiones relacionadas