Compruebe si una cadena es una ruta válida de directorio (carpeta) de Windows

84

Estoy tratando de determinar si una cadena de entrada de un usuario es válida para representar una ruta a una carpeta. Por válido, me refiero a formateado correctamente.

En mi aplicación, la carpeta representa un destino de instalación. Siempre que la ruta de la carpeta sea válida, quiero determinar si la carpeta existe y crearla si no es así.

Actualmente estoy usando IO.Directory.Exists( String path ). Encuentro que esto funciona bien, excepto cuando el usuario no formatea la cadena correctamente. Cuando eso sucede, este método devolverá falso, lo que indica que la carpeta no existe. Pero esto es un problema porque no podré crear la carpeta después.

En mi búsqueda en Google encontré una sugerencia para usar una expresión regular para verificar si el formato es el adecuado. No tengo experiencia con las expresiones regulares y me pregunto si ese es un enfoque viable. Esto es lo que encontré:

Regex r = new Regex( @"^(([a-zA-Z]\:)|(\\))(\\{1}|((\\{1})[^\\]([^/:*?<>""|]*))+)$" );
return r.IsMatch( path );

¿Una prueba de expresión regular en combinación con Directory.Exists(), me proporcionaría un método suficientemente bueno para verificar si la ruta es válida y si existe? Sé que esto variará según el sistema operativo y otros factores, pero el programa está dirigido solo a usuarios de Windows .

Pudpuduk
fuente
1
Si no crea el directorio después de que Directory.Exists devuelve falso, ¿no es una buena indicación de que el usuario proporcionó una entrada incorrecta?
Robert Harvey
2
@RobertI vi esa pregunta y no proporcionó una respuesta específica más que las reglas generales. La segunda respuesta más alta no cubrió el formato, sino solo los caracteres no válidos. Además, el método Directory.Exists puede devolver falso, pero como quiero la opción de crear la carpeta en el lugar, no puedo simplemente seguir eso.
Pudpuduk
@Robert Sobre el segundo tema que vinculó, escribir una sola palabra aún pasaría la validación dada en las respuestas a esa pregunta.
Pudpuduk

Respuestas:

116

Llamada Path.GetFullPath ; arrojará excepciones si la ruta no es válida.

Para no permitir rutas relativas (como Word), llame a Path.IsPathRooted.

SLaks
fuente
¡Sabía que había algo más simple! Y gracias, no pensé en el problema de que los caminos son relativos.
Pudpuduk
2
Gracias SLaks. He visto muchos duplicados y he realizado muchas búsquedas en Google (en más de una ocasión), pero esta es la primera vez que veo una buena respuesta a esta pregunta en particular.
Robert Harvey
5
Path.GetFullPath ("con.txt") es un nombre de archivo válido.
Christoffer
8
@Slaks Esto es demasiado antiguo para dejar un comentario, pero aún quiero dejar uno aquí por la razón por la que les di mi voto de -1. Path.GetFullPath () parece funcionar bien, pero ¿qué pasa si la ruta es: "Z: \\\\\\\\ Hola \\\\\\", no es una ruta absoluta válida sino la ruta Path.GetFullPath (...) da el resultado: Z: \ Hola \ Ahí y no se plantea ninguna excepción. Tuve que cambiarlo un poco comparando la cadena devuelta por GetFullPath () y la cadena original así: private bool IsPathValid (ruta de la cadena) {try {string fullPath = Path.GetFullPath (ruta); return fullPath == ruta; } catch {return false;}}
King King
4
@KingKing De esta respuesta de Linux en unix.stackexchange.com: "Se permiten varias barras y son equivalentes a una sola barra ..." He observado lo mismo en Windows (aunque las barras principales en una ruta UNC pueden tratarse de manera diferente). Como prueba de esto, en un símbolo del sistema, intente lo siguiente: cd C:\\\\\\\Windows\\\\\\\System32. Para Windows, no puedo encontrar una fuente autorizada que documente este comportamiento, pero, por supuesto, agradecería un puntero a uno.
DavidRR
20

De hecho, no estoy de acuerdo con SLaks. Esa solución no funcionó para mí. La excepción no sucedió como se esperaba. Pero este código funcionó para mí:

if(System.IO.Directory.Exists(path))
{
    ...
}
Scott Shaw-Smith
fuente
62
Una ruta válida no es necesariamente un directorio que existe ... que es exactamente el problema que se plantea aquí
Benlitz
1
La pregunta estaba relacionada con la validación de la cadena de ruta, una ruta que podría no existir.
Mubashar
Creo que esta forma es correcta. No se deben esperar excepciones. Este método también verifica los caracteres incorrectos en la ruta dada.
Eugene Maksimov
Esta condición generará una excepción en sí misma si la "ruta" no se encuentra como una ruta real ya que Directory.Exists requiere una ruta válida.
M. Fawad Surosh
¡Respuesta completamente incorrecta! Me pregunto cómo recibió 32 votos a favor (a partir de ahora). Debe ser de personas que estaban buscando en el lugar equivocado para el problema que estaban enfrentando, y se encontraron con esto.
Sнаđошƒаӽ
13

Path.GetFullPath da solo las siguientes excepciones

La ruta de ArgumentException es una cadena de longitud cero, contiene solo espacios en blanco o contiene uno o más de los caracteres no válidos definidos en GetInvalidPathChars. -o bien - El sistema no pudo recuperar la ruta absoluta.

SecurityException La persona que llama no tiene los permisos necesarios.

La ruta de ArgumentNullException es nula.

La ruta NotSupportedException contiene dos puntos (":") que no forman parte de un identificador de volumen (por ejemplo, "c: \").

PathTooLongException La ruta especificada, el nombre de archivo o ambos exceden la longitud máxima definida por el sistema. Por ejemplo, en las plataformas basadas en Windows, las rutas deben tener menos de 248 caracteres y los nombres de archivo deben tener menos de 260 caracteres.

La forma alternativa es utilizar lo siguiente:

/// <summary>
/// Validate the Path. If path is relative append the path to the project directory by default.
/// </summary>
/// <param name="path">Path to validate</param>
/// <param name="RelativePath">Relative path</param>
/// <param name="Extension">If want to check for File Path</param>
/// <returns></returns>
private static bool ValidateDllPath(ref string path, string RelativePath = "", string Extension = "")
{
    // Check if it contains any Invalid Characters.
    if (path.IndexOfAny(Path.GetInvalidPathChars()) == -1)
    {
        try
        {
            // If path is relative take %IGXLROOT% as the base directory
            if (!Path.IsPathRooted(path))
            {
                if (string.IsNullOrEmpty(RelativePath))
                {
                    // Exceptions handled by Path.GetFullPath
                    // ArgumentException path is a zero-length string, contains only white space, or contains one or more of the invalid characters defined in GetInvalidPathChars. -or- The system could not retrieve the absolute path.
                    // 
                    // SecurityException The caller does not have the required permissions.
                    // 
                    // ArgumentNullException path is null.
                    // 
                    // NotSupportedException path contains a colon (":") that is not part of a volume identifier (for example, "c:\"). 
                    // PathTooLongException The specified path, file name, or both exceed the system-defined maximum length. For example, on Windows-based platforms, paths must be less than 248 characters, and file names must be less than 260 characters.

                    // RelativePath is not passed so we would take the project path 
                    path = Path.GetFullPath(RelativePath);

                }
                else
                {
                    // Make sure the path is relative to the RelativePath and not our project directory
                    path = Path.Combine(RelativePath, path);
                }
            }

            // Exceptions from FileInfo Constructor:
            //   System.ArgumentNullException:
            //     fileName is null.
            //
            //   System.Security.SecurityException:
            //     The caller does not have the required permission.
            //
            //   System.ArgumentException:
            //     The file name is empty, contains only white spaces, or contains invalid characters.
            //
            //   System.IO.PathTooLongException:
            //     The specified path, file name, or both exceed the system-defined maximum
            //     length. For example, on Windows-based platforms, paths must be less than
            //     248 characters, and file names must be less than 260 characters.
            //
            //   System.NotSupportedException:
            //     fileName contains a colon (:) in the middle of the string.
            FileInfo fileInfo = new FileInfo(path);

            // Exceptions using FileInfo.Length:
            //   System.IO.IOException:
            //     System.IO.FileSystemInfo.Refresh() cannot update the state of the file or
            //     directory.
            //
            //   System.IO.FileNotFoundException:
            //     The file does not exist.-or- The Length property is called for a directory.
            bool throwEx = fileInfo.Length == -1;

            // Exceptions using FileInfo.IsReadOnly:
            //   System.UnauthorizedAccessException:
            //     Access to fileName is denied.
            //     The file described by the current System.IO.FileInfo object is read-only.-or-
            //     This operation is not supported on the current platform.-or- The caller does
            //     not have the required permission.
            throwEx = fileInfo.IsReadOnly;

            if (!string.IsNullOrEmpty(Extension))
            {
                // Validate the Extension of the file.
                if (Path.GetExtension(path).Equals(Extension, StringComparison.InvariantCultureIgnoreCase))
                {
                    // Trim the Library Path
                    path = path.Trim();
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return true;

            }
        }
        catch (ArgumentNullException)
        {
            //   System.ArgumentNullException:
            //     fileName is null.
        }
        catch (System.Security.SecurityException)
        {
            //   System.Security.SecurityException:
            //     The caller does not have the required permission.
        }
        catch (ArgumentException)
        {
            //   System.ArgumentException:
            //     The file name is empty, contains only white spaces, or contains invalid characters.
        }
        catch (UnauthorizedAccessException)
        {
            //   System.UnauthorizedAccessException:
            //     Access to fileName is denied.
        }
        catch (PathTooLongException)
        {
            //   System.IO.PathTooLongException:
            //     The specified path, file name, or both exceed the system-defined maximum
            //     length. For example, on Windows-based platforms, paths must be less than
            //     248 characters, and file names must be less than 260 characters.
        }
        catch (NotSupportedException)
        {
            //   System.NotSupportedException:
            //     fileName contains a colon (:) in the middle of the string.
        }
        catch (FileNotFoundException)
        {
            // System.FileNotFoundException
            //  The exception that is thrown when an attempt to access a file that does not
            //  exist on disk fails.
        }
        catch (IOException)
        {
            //   System.IO.IOException:
            //     An I/O error occurred while opening the file.
        }
        catch (Exception)
        {
            // Unknown Exception. Might be due to wrong case or nulll checks.
        }
    }
    else
    {
        // Path contains invalid characters
    }
    return false;
}
vCilusión
fuente
9

Aquí hay una solución que aprovecha el uso de Path.GetFullPath como se recomienda en la respuesta de @SLaks .

En el código que incluyo aquí, tenga en cuenta que IsValidPath(string path)está diseñado de tal manera que la persona que llama no tiene que preocuparse por el manejo de excepciones .

También puede encontrar que el método al que llama, TryGetFullPath(...)también tiene mérito por sí solo cuando desea intentar con seguridad obtener una ruta absoluta .

/// <summary>
/// Gets a value that indicates whether <paramref name="path"/>
/// is a valid path.
/// </summary>
/// <returns>Returns <c>true</c> if <paramref name="path"/> is a
/// valid path; <c>false</c> otherwise. Also returns <c>false</c> if
/// the caller does not have the required permissions to access
/// <paramref name="path"/>.
/// </returns>
/// <seealso cref="Path.GetFullPath"/>
/// <seealso cref="TryGetFullPath"/>
public static bool IsValidPath(string path)
{
    string result;
    return TryGetFullPath(path, out result);
}

/// <summary>
/// Returns the absolute path for the specified path string. A return
/// value indicates whether the conversion succeeded.
/// </summary>
/// <param name="path">The file or directory for which to obtain absolute
/// path information.
/// </param>
/// <param name="result">When this method returns, contains the absolute
/// path representation of <paramref name="path"/>, if the conversion
/// succeeded, or <see cref="String.Empty"/> if the conversion failed.
/// The conversion fails if <paramref name="path"/> is null or
/// <see cref="String.Empty"/>, or is not of the correct format. This
/// parameter is passed uninitialized; any value originally supplied
/// in <paramref name="result"/> will be overwritten.
/// </param>
/// <returns><c>true</c> if <paramref name="path"/> was converted
/// to an absolute path successfully; otherwise, false.
/// </returns>
/// <seealso cref="Path.GetFullPath"/>
/// <seealso cref="IsValidPath"/>
public static bool TryGetFullPath(string path, out string result)
{
    result = String.Empty;
    if (String.IsNullOrWhiteSpace(path)) { return false; }
    bool status = false;

    try
    {
        result = Path.GetFullPath(path);
        status = true;
    }
    catch (ArgumentException) { }
    catch (SecurityException) { }
    catch (NotSupportedException) { }
    catch (PathTooLongException) { }

    return status;
}
DavidRR
fuente
6

Use este código

string DirectoryName = "Sample Name For Directory Or File";
Path.GetInvalidFileNameChars()
  .Where(x => DirectoryName.Contains(x))
  .Count() > 0 || DirectoryName == "con"
usuario1508188
fuente
4
Código un poco más corto que logra lo mismo: Path.GetInvalidFileNameChars().Any(DirectoryName.Contains) || DirectoryName == "con"
bsegraves
2
@nawfal De hecho. De Nombrar archivos, rutas y espacios de nombres en MSDN: "No utilice los siguientes nombres reservados para el nombre de un archivo: CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8 y LPT9. También evite estos nombres seguidos inmediatamente de una extensión; por ejemplo, no se recomienda NUL.txt. Para obtener más información, consulte Espacios de nombres ".
DavidRR
Este "aproach lista negra" no funciona en todos los sistemas de Windows, por ejemplo cuando un pictografías muestra arriba: en.wikipedia.org/wiki/Miscellaneous_Symbols_and_Pictographs
Ene
4
    private bool IsValidPath(string path)
    {
        Regex driveCheck = new Regex(@"^[a-zA-Z]:\\$");
        if (!driveCheck.IsMatch(path.Substring(0, 3))) return false;
        string strTheseAreInvalidFileNameChars = new string(Path.GetInvalidPathChars());
        strTheseAreInvalidFileNameChars += @":/?*" + "\"";
        Regex containsABadCharacter = new Regex("[" + Regex.Escape(strTheseAreInvalidFileNameChars) + "]");
        if (containsABadCharacter.IsMatch(path.Substring(3, path.Length - 3)))
            return false;

        DirectoryInfo dir = new DirectoryInfo(Path.GetFullPath(path));
        if (!dir.Exists)
            dir.Create();
        return true;
    }
Alex Jolig
fuente
3

No he tenido ningún problema con este código:

private bool IsValidPath(string path, bool exactPath = true)
{
    bool isValid = true;

    try
    {
        string fullPath = Path.GetFullPath(path);

        if (exactPath)
        {
            string root = Path.GetPathRoot(path);
            isValid = string.IsNullOrEmpty(root.Trim(new char[] { '\\', '/' })) == false;
        }
        else
        {
            isValid = Path.IsPathRooted(path);
        }
    }
    catch(Exception ex)
    {
        isValid = false;
    }

    return isValid;
}

Por ejemplo, estos devolverían falso:

IsValidPath("C:/abc*d");
IsValidPath("C:/abc?d");
IsValidPath("C:/abc\"d");
IsValidPath("C:/abc<d");
IsValidPath("C:/abc>d");
IsValidPath("C:/abc|d");
IsValidPath("C:/abc:d");
IsValidPath("");
IsValidPath("./abc");
IsValidPath("/abc");
IsValidPath("abc");
IsValidPath("abc", false);

Y estos volverían verdaderos:

IsValidPath(@"C:\\abc");
IsValidPath(@"F:\FILES\");
IsValidPath(@"C:\\abc.docx\\defg.docx");
IsValidPath(@"C:/abc/defg");
IsValidPath(@"C:\\\//\/\\/\\\/abc/\/\/\/\///\\\//\defg");
IsValidPath(@"C:/abc/def~`!@#$%^&()_-+={[}];',.g");
IsValidPath(@"C:\\\\\abc////////defg");
IsValidPath(@"/abc", false);
Buscador de Dao
fuente
0

Una solución independiente del sistema operativo más sencilla.

public static class PathHelper
{
    public static void ValidatePath(string path)
    {
        if (!Directory.Exists(path))
            Directory.CreateDirectory(path).Delete();
    }
}

Uso:

try
{
    PathHelper.ValidatePath(path);
}
catch(Exception e)
{
    // handle exception
}

Directory.CreateDirectory() arrojará automáticamente en todas las situaciones siguientes:

System.IO.IOException:
el directorio especificado por ruta es un archivo. -o bien - No se conoce el nombre de la red.

System.UnauthorizedAccessException:
la persona que llama no tiene el permiso requerido.

System.ArgumentException:
ruta es una cadena de longitud cero, contiene solo espacios en blanco o contiene uno o más caracteres no válidos. Puede consultar caracteres no válidos mediante el método System.IO.Path.GetInvalidPathChars. O bien, la ruta tiene el prefijo o contiene solo un carácter de dos puntos (:).

System.ArgumentNullException:
ruta es nula.

System.IO.PathTooLongException:
la ruta especificada, el nombre de archivo o ambos exceden la longitud máxima definida por el sistema.

System.IO.DirectoryNotFoundException:
la ruta especificada no es válida (por ejemplo, está en una unidad sin asignar).

System.NotSupportedException: la
ruta contiene un carácter de dos puntos (:) que no es parte de una etiqueta de unidad ("C:").

Engancharse
fuente