.net path illegal-characters

.Net: ¿Cómo verifico si hay caracteres ilegales en una ruta?



path illegal-characters (6)

A partir de .NET 4.7.2 , Path.GetInvalidFileNameChars() informa los siguientes 41 caracteres "incorrectos".

0x0000 0 ''/0'' | 0x000d 13 ''/r'' | 0x001b 27 ''/u001b'' 0x0001 1 ''/u0001'' | 0x000e 14 ''/u000e'' | 0x001c 28 ''/u001c'' 0x0002 2 ''/u0002'' | 0x000f 15 ''/u000f'' | 0x001d 29 ''/u001d'' 0x0003 3 ''/u0003'' | 0x0010 16 ''/u0010'' | 0x001e 30 ''/u001e'' 0x0004 4 ''/u0004'' | 0x0011 17 ''/u0011'' | 0x001f 31 ''/u001f'' 0x0005 5 ''/u0005'' | 0x0012 18 ''/u0012'' | 0x0022 34 ''"'' 0x0006 6 ''/u0006'' | 0x0013 19 ''/u0013'' | 0x002a 42 ''*'' 0x0007 7 ''/a'' | 0x0014 20 ''/u0014'' | 0x002f 47 ''/'' 0x0008 8 ''/b'' | 0x0015 21 ''/u0015'' | 0x003a 58 '':'' 0x0009 9 ''/t'' | 0x0016 22 ''/u0016'' | 0x003c 60 ''<'' 0x000a 10 ''/n'' | 0x0017 23 ''/u0017'' | 0x003e 62 ''>'' 0x000b 11 ''/v'' | 0x0018 24 ''/u0018'' | 0x003f 63 ''?'' 0x000c 12 ''/f'' | 0x0019 25 ''/u0019'' | 0x005c 92 ''//' | 0x001a 26 ''/u001a'' | 0x007c 124 ''|''

Como lo noted otro póster, este es un superconjunto apropiado del conjunto de caracteres devueltos por Path.GetInvalidPathChars() . Puede usar la siguiente línea de código para detectar este conjunto exacto de caracteres:

public static bool IsInvalidFileNameChar(Char c) => c < 64U ? (1UL << c & 0xD4008404FFFFFFFFUL) != 0 : c == ''//' || c == ''|'';

¿Hay alguna forma de verificar si una cadena diseñada para una ruta tiene caracteres no válidos, en .Net? Sé que podría recorrer cada carácter en Path.InvalidPathChars para ver si mi String contenía uno, pero preferiría una solución simple, quizás más formal.

Hay uno

Descubrí que todavía recibo una excepción si solo comparo con Get

Actualizar:

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

Actualización 2:

GetInvalidFileNameChars definitivamente no es lo que quiero. Contiene '':'', que contendrá cualquier ruta absoluta ("C: / lo que sea"). 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.


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

Edición: Ligeramente más largo, pero maneja 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; }


Probablemente sea demasiado tarde para ti, pero puede ayudar a alguien más. Me enfrenté al mismo problema y necesitaba encontrar una manera 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: Comprueba cualquier carácter no válido aún no eliminado.

Como paso de verificación adicional, utilizo el método Path.GetInvalidPathChars() publicado anteriormente para detectar posibles caracteres no válidos que aún no se Path.GetInvalidPathChars() eliminado.

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

Paso 3: Limpie cualquier carácter especial detectado en el Paso 2.

Y, finalmente, utilizo este método como paso final para limpiar todo lo que queda. (de ¿Cómo eliminar los caracteres ilegales de la ruta y los nombres de archivo? ):

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

Registro cualquier carácter no válido no limpiado en el primer paso. Elijo ir por ese camino para mejorar mi método personalizado tan pronto como se detecte una "fuga". No puedo confiar en Path.GetInvalidFileNameChars() debido a la siguiente declaración que se informó anteriormente (de MSDN):

"No se garantiza que la matriz devuelta por este método contenga el conjunto completo de caracteres que no son válidos en los nombres de archivos y directorios".

Puede que no sea la solución ideal, pero dado el contexto de mi aplicación y el nivel de confiabilidad requerido, esta es la mejor solución que encontré.


También soy demasiado tarde. Pero si la tarea es validar si el usuario ingresó algo válido como ruta, hay una solución combinada para las rutas.

Path.GetInvalidFileNameChars() devuelve una lista de caracteres no Path.GetInvalidFileNameChars() para el archivo, pero el directorio sigue las reglas del archivo, excepto los separadores (que podríamos obtener del sistema) y el especificador de la raíz ( C: simplemente podemos eliminarlo de la búsqueda). Sí, Path.GetInvalidFileNameChars() no devuelve el conjunto completo, pero es mejor que tratar de encontrarlos todos manualmente.

Asi que:

private static bool CheckInvalidPath(string targetDir) { string root; try { root = Path.GetPathRoot(targetDir); } catch { // the path is definitely invalid if it has crashed return false; } // of course it is better to cache it as it creates // new array on each call char[] chars = Path.GetInvalidFileNameChars(); // ignore root for (int i = root.Length; i < targetDir.Length; i++) { char c = targetDir[i]; // separators are allowed if (c == Path.DirectorySeparatorChar || c == Path.AltDirectorySeparatorChar) continue; // check for illegal chars for (int j = 0; j < chars.Length; j++) if (c == chars[j]) return false; } return true; }

Descubrí que los métodos como Path.GetFileName no se bloquearán para las rutas como C:/* (que es completamente inválida) e incluso una verificación basada en excepciones no es suficiente. Lo único que bloqueará el Path.GetPathRoot es una raíz no válida (como CC:/someDir ). Así que todo lo demás debe hacerse manualmente.


Tenga cuidado al confiar en Path.GetInvalidFileNameChars , que puede no ser tan confiable como podría pensar. Observe el siguiente comentario en la documentación de MSDN en Path.GetInvalidFileNameChars :

No se garantiza que la matriz devuelta por este método contenga 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 no válidos pueden incluir los caracteres ASCII / Unicode 1 a 31, así como comillas ("), menores que (<), mayores que (>), canalizaciones (|), retroceso ( / b), nulo (/ 0) y tabulador (/ t).

No es mejor con el método Path.GetInvalidPathChars . Contiene exactamente el mismo comentario.


Terminé tomando prestado y combinando algunas implementaciones internas de .NET para crear un método de ejecución:

/// <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, pero también lo envolví en un bloque try / catch por seguridad:

if ( !string.IsNullOrWhiteSpace(path) && !ContainsInvalidPathCharacters(path)) { FileInfo fileInfo = null; try { fileInfo = new FileInfo(path); } catch (ArgumentException) { } ... }