Compruebe si se proporciona la ruta completa

104

¿Existe un método para verificar si la ruta dada es la ruta completa? Ahora mismo estoy haciendo esto:

if (template.Contains(":\\")) //full path already given
{
}
else //calculate the path from local assembly
{
}

¿Pero debe haber una forma más elegante de comprobar esto?

hs2d
fuente

Respuestas:

141

Intente usar System.IO.Path.IsPathRooted? También regresa truepara rutas absolutas.

System.IO.Path.IsPathRooted(@"c:\foo"); // true
System.IO.Path.IsPathRooted(@"\foo"); // true
System.IO.Path.IsPathRooted("foo"); // false

System.IO.Path.IsPathRooted(@"c:1\foo"); // surprisingly also true
System.IO.Path.GetFullPath(@"c:1\foo");// returns "[current working directory]\1\foo"
detaylor
fuente
14
¿Por qué el segundo ejemplo es la ruta absoluta?
om471987
4
El segundo camino no es absoluto, sin embargo está arraigado. La barra inclinada indica la raíz del sistema.
detaylor
3
@SmirkinGherkin entonces, ¿cuál es la diferencia entre una ruta arraigada y absoluta?
Jason Axelson
1
Consulte mi respuesta ( stackoverflow.com/a/35046453/704808 ) para ver una alternativa que garantiza una ruta completa y conserva las ventajas de IsPathRooted: evitar el acceso al sistema de archivos o lanzar excepciones para entradas no válidas.
vertedero
1
@daniel, IIRC se incluyó para mostrar que la ruta no necesitaba ser una ruta válida para ser utilizada IsPathRooted, ciertamente no era nada significativo. La GetFullPathlínea se incluyó para que se pudiera observar el camino que se está evaluando
detaylor
30
Path.IsPathRooted(path)
&& !Path.GetPathRoot(path).Equals(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)

La condición anterior:

  • no requiere permisos del sistema de archivos
  • devuelve falseen la mayoría de los casos donde el formato de pathno es válido (en lugar de lanzar una excepción)
  • devuelve truesolo si pathincluye el volumen

En escenarios como el que planteó el OP, por lo tanto, puede ser más adecuado que las condiciones en las respuestas anteriores. A diferencia de la condición anterior:

  • path == System.IO.Path.GetFullPath(path)arroja excepciones en lugar de regresar falseen estos escenarios:
    • La persona que llama no tiene los permisos necesarios
    • El sistema no pudo recuperar la ruta absoluta
    • la ruta contiene dos puntos (":") que no forman parte de un identificador de volumen
    • La ruta especificada, el nombre de archivo o ambos exceden la longitud máxima definida por el sistema
  • System.IO.Path.IsPathRooted(path)devuelve truesi pathcomienza con un solo separador de directorio.

Finalmente, aquí hay un método que envuelve la condición anterior y también excluye las posibles excepciones restantes:

public static bool IsFullPath(string path) {
    return !String.IsNullOrWhiteSpace(path)
        && path.IndexOfAny(System.IO.Path.GetInvalidPathChars().ToArray()) == -1
        && Path.IsPathRooted(path)
        && !Path.GetPathRoot(path).Equals(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal);
}

EDITAR: EM0 hizo un buen comentario y respuesta alternativa abordando el curioso caso de caminos como C:y C:dir. Para ayudar a decidir cómo desea manejar tales rutas, es posible que desee profundizar en MSDN -> Aplicaciones de escritorio de Windows -> Desarrollar -> Tecnologías de escritorio -> Acceso y almacenamiento de datos -> Sistemas de archivos locales - -> Administración de archivos -> Acerca de la administración de archivos -> Creación, eliminación y mantenimiento de archivos -> Asignación de nombres a archivos, rutas y espacios de nombres -> Rutas totalmente calificadas frente a rutas relativas

Para las funciones de la API de Windows que manipulan archivos, los nombres de los archivos a menudo pueden ser relativos al directorio actual, mientras que algunas API requieren una ruta completamente calificada. Un nombre de archivo es relativo al directorio actual si no comienza con uno de los siguientes:

  • Un nombre UNC de cualquier formato, que siempre comienza con dos caracteres de barra invertida ("\"). Para obtener más información, consulte la siguiente sección.
  • Un designador de disco con barra invertida, por ejemplo, "C: \" o "d: \".
  • Una sola barra invertida, por ejemplo, "\ directorio" o "\ archivo.txt". Esto también se conoce como ruta absoluta.

Si un nombre de archivo comienza solo con un designador de disco pero no con la barra invertida después de los dos puntos, se interpreta como una ruta relativa al directorio actual en la unidad con la letra especificada. Tenga en cuenta que el directorio actual puede ser o no el directorio raíz, dependiendo de lo que se configuró durante la operación de "cambio de directorio" más reciente en ese disco. Ejemplos de este formato son los siguientes:

  • "C: tmp.txt" se refiere a un archivo llamado "tmp.txt" en el directorio actual de la unidad C.
  • "C: tempdir \ tmp.txt" se refiere a un archivo en un subdirectorio del directorio actual en la unidad C.

[...]

presa
fuente
3
Me gusta que esto no arroje para rutas no válidas, pero devuelve verdadero para rutas como "C:" y "C: dir", que son resueltas por GetFullPath usando el directorio actual (por lo que no son absolutas). Publicó una respuesta que devuelve falso para estos.
EM0
@ EM0 - ¡Gracias! Me acabas de enseñar algo. :)
vertedero
15

Tratar

System.IO.Path.IsPathRooted(template)

Funciona tanto para rutas UNC como locales.

P.ej

Path.IsPathRooted(@"\\MyServer\MyShare\MyDirectory")  // returns true
Path.IsPathRooted(@"C:\\MyDirectory")  // returns true
Joe
fuente
13

Pregunta antigua, pero una respuesta más aplicable. Si necesita asegurarse de que el volumen esté incluido en una ruta local, puede usar System.IO.Path.GetFullPath () así:

if (template == System.IO.Path.GetFullPath(template))
{
    ; //template is full path including volume or full UNC path
}
else
{
    if (useCurrentPathAndVolume)
        template = System.IO.Path.GetFullPath(template);
    else
        template = Assembly.GetExecutingAssembly().Location
}
GreggD
fuente
3
Esto era lo que necesitaba, y parece más cercano a la pregunta original, ya que IsPathRooted 'devuelve verdadero para rutas relativas (no necesariamente rutas absolutas)
bitcoder
GetFullPathaccede al sistema de archivos y puede generar una serie de posibles excepciones. Vea mi respuesta ( stackoverflow.com/a/35046453/704808 ) para ver una alternativa que aún garantiza una ruta completa.
vertedero
11

Basándose en la respuesta de weir : esto no arroja rutas no válidas, sino que también devuelve falserutas como "C:", "C: dirname" y "\ ruta".

public static bool IsFullPath(string path)
{
    if (string.IsNullOrWhiteSpace(path) || path.IndexOfAny(Path.GetInvalidPathChars()) != -1 || !Path.IsPathRooted(path))
        return false;

    string pathRoot = Path.GetPathRoot(path);
    if (pathRoot.Length <= 2 && pathRoot != "/") // Accepts X:\ and \\UNC\PATH, rejects empty string, \ and X:, but accepts / to support Linux
        return false;

    if (pathRoot[0] != '\\' || pathRoot[1] != '\\')
        return true; // Rooted and not a UNC path

    return pathRoot.Trim('\\').IndexOf('\\') != -1; // A UNC server name without a share name (e.g "\\NAME" or "\\NAME\") is invalid
}

Tenga en cuenta que esto arroja resultados diferentes en Windows y Linux, por ejemplo, "/ ruta" es absoluto en Linux, pero no en Windows.

Prueba de unidad:

[Test]
public void IsFullPath()
{
    bool isWindows = Environment.OSVersion.Platform.ToString().StartsWith("Win"); // .NET Framework
    // bool isWindows = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows); // .NET Core

    // These are full paths on Windows, but not on Linux
    TryIsFullPath(@"C:\dir\file.ext", isWindows);
    TryIsFullPath(@"C:\dir\", isWindows);
    TryIsFullPath(@"C:\dir", isWindows);
    TryIsFullPath(@"C:\", isWindows);
    TryIsFullPath(@"\\unc\share\dir\file.ext", isWindows);
    TryIsFullPath(@"\\unc\share", isWindows);

    // These are full paths on Linux, but not on Windows
    TryIsFullPath(@"/some/file", !isWindows);
    TryIsFullPath(@"/dir", !isWindows);
    TryIsFullPath(@"/", !isWindows);

    // Not full paths on either Windows or Linux
    TryIsFullPath(@"file.ext", false);
    TryIsFullPath(@"dir\file.ext", false);
    TryIsFullPath(@"\dir\file.ext", false);
    TryIsFullPath(@"C:", false);
    TryIsFullPath(@"C:dir\file.ext", false);
    TryIsFullPath(@"\dir", false); // An "absolute", but not "full" path

    // Invalid on both Windows and Linux
    TryIsFullPath(null, false, false);
    TryIsFullPath("", false, false);
    TryIsFullPath("   ", false, false);
    TryIsFullPath(@"C:\inval|d", false, false);
    TryIsFullPath(@"\\is_this_a_dir_or_a_hostname", false, false);
    TryIsFullPath(@"\\is_this_a_dir_or_a_hostname\", false, !isWindows);
    TryIsFullPath(@"\\is_this_a_dir_or_a_hostname\\", false, !isWindows);
}

private static void TryIsFullPath(string path, bool expectedIsFull, bool expectedIsValid = true)
{
    Assert.AreEqual(expectedIsFull, PathUtils.IsFullPath(path), "IsFullPath('" + path + "')");

    if (expectedIsFull)
    {
        Assert.AreEqual(path, Path.GetFullPath(path));
    }
    else if (expectedIsValid)
    {
        Assert.AreNotEqual(path, Path.GetFullPath(path));
    }
    else
    {
        Assert.That(() => Path.GetFullPath(path), Throws.Exception);
    }
}
EM0
fuente
Buen material. Noté que msdn.microsoft.com/en-us/library/windows/desktop/… indica que en Windows una ruta no es relativa si comienza con 'Una sola barra invertida, por ejemplo, "\ directorio" o "\ archivo .TXT". Esto también se conoce como ruta absoluta. '
vertedero
1
¡Buen punto! Parece que mi terminología estaba mal. Cuando dije "ruta absoluta", realmente estaba pensando en lo que la EM llama "ruta completa". Cambié el nombre y agregué un caso de prueba para esto.
EM0
1
Gracias por esta respuesta, me ayudó mucho. Sin embargo, tenga en cuenta que para una ruta UNC como \\ servidor \, el método devuelve verdadero, pero esto generará una excepción si luego llama a Directory.Exists (ruta) (System.ArgumentException: 'La ruta UNC debe ser de la forma \\ servidor \ compartir. ')
Carl
2
Es bueno ver que la gente sigue usando esto y encuentra nuevos casos extremos. @Carl ¡Actualizó el código y pruebe eso!
EM0
6

Para verificar si una ruta está completamente calificada (MSDN) :

public static bool IsPathFullyQualified(string path)
{
    var root = Path.GetPathRoot(path);
    return root.StartsWith(@"\\") || root.EndsWith(@"\");
}

Es un poco más simple de lo que ya se ha propuesto y todavía devuelve falso para rutas relativas a unidades como C:foo. Su lógica se basa directamente en la definición de MSDN de "totalmente calificado", y no he encontrado ningún ejemplo en el que se comporte mal.


Curiosamente, sin embargo, .NET Core 2.1 parece tener un nuevo método Path.IsPathFullyQualifiedque utiliza un método interno PathInternal.IsPartiallyQualified(la ubicación del enlace es precisa a partir de 2018-04-17).

Para la posteridad y una mejor autocontención de esta publicación, aquí está la implementación de esta última como referencia:

internal static bool IsPartiallyQualified(ReadOnlySpan<char> path)
{
    if (path.Length < 2)
    {
        // It isn't fixed, it must be relative.  There is no way to specify a fixed
        // path with one character (or less).
        return true;
    }

    if (IsDirectorySeparator(path[0]))
    {
        // There is no valid way to specify a relative path with two initial slashes or
        // \? as ? isn't valid for drive relative paths and \??\ is equivalent to \\?\
        return !(path[1] == '?' || IsDirectorySeparator(path[1]));
    }

    // The only way to specify a fixed path that doesn't begin with two slashes
    // is the drive, colon, slash format- i.e. C:\
    return !((path.Length >= 3)
        && (path[1] == VolumeSeparatorChar)
        && IsDirectorySeparator(path[2])
        // To match old behavior we'll check the drive character for validity as the path is technically
        // not qualified if you don't have a valid drive. "=:\" is the "=" file's default data stream.
        && IsValidDriveChar(path[0]));
}
Guillermo
fuente
4

Esta es la solución que uso

public static bool IsFullPath(string path)
{
    try
    {
        return Path.GetFullPath(path) == path;
    }
    catch
    {
        return false;
    }
}

Funciona de la siguiente manera:

IsFullPath(@"c:\foo"); // true
IsFullPath(@"C:\foo"); // true
IsFullPath(@"c:\foo\"); // true
IsFullPath(@"c:/foo"); // false
IsFullPath(@"\foo"); // false
IsFullPath(@"foo"); // false
IsFullPath(@"c:1\foo\"); // false
Mykhailo Seniutovych
fuente
¡Muy interesante! Es frágil, por ejemplo, tiene que coincidir con los tipos de barra, pero esto es prometedor.
Nicholas Petersen
Devuelve resultados incorrectos para las siguientes rutas: C:\foo\..\foooC:\foo\.\.\.
sergtk
1

Llame a la siguiente función:

Path.IsPathFullyQualified(@"c:\foo")

Documento de MSDN: Método Path.IsPathFullyQualified

La cita útil del documento de MSDN sigue:

Este método maneja rutas que usan el separador de directorio alternativo. Es un error frecuente asumir que las rutas enraizadas ( IsPathRooted (String) ) no son relativas. Por ejemplo, "C: a" es relativo a la unidad, es decir, se resuelve en el directorio actual de C: (arraigado, pero relativo). "C: \ a" está enraizado y no es relativo, es decir, el directorio actual no se usa para modificar la ruta.

sergtk
fuente
0

No estoy realmente seguro de lo que quiere decir con ruta completa (aunque asumiendo del ejemplo que quiere decir no relativo desde la raíz en adelante), bueno, puede usar la clase Path para ayudarlo a trabajar con rutas físicas del sistema de archivos, que deberían cubrir usted para la mayoría de las eventualidades.

Grant Thomas
fuente