Vérifiez si le chemin complet est donné

104

Existe-t-il une méthode pour vérifier si le chemin donné est un chemin complet? En ce moment, je fais ceci:

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

Mais il doit y avoir un moyen plus élégant de vérifier cela?

hs2d
la source

Réponses:

141

Essayez d'utiliser System.IO.Path.IsPathRooted? Il renvoie également truepour les chemins absolus.

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
la source
14
Comment se fait-il que le deuxième exemple soit un chemin absolu?
om471987
4
Le deuxième chemin n'est pas absolu, mais il est enraciné. La barre oblique principale indique la racine du système.
detaylor le
3
@SmirkinGherkin alors quelle est la différence entre un chemin enraciné et absolu?
Jason Axelson
1
Voir ma réponse ( stackoverflow.com/a/35046453/704808 ) pour une alternative qui assure un chemin complet tout en conservant les avantages de IsPathRooted: éviter d'accéder au système de fichiers ou de lever des exceptions pour une entrée invalide.
déversoir le
1
@daniel, IIRC, il a été inclus pour montrer que le chemin n'avait pas besoin d'être un chemin valide pour être utilisé IsPathRooted, ce n'était certainement rien de significatif. La GetFullPathligne a été incluse afin que le chemin en cours d'évaluation puisse être observé
détaylor
30
Path.IsPathRooted(path)
&& !Path.GetPathRoot(path).Equals(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)

La condition ci-dessus:

  • ne nécessite pas d'autorisations de système de fichiers
  • renvoie falsedans la plupart des cas où le format de pathn'est pas valide (plutôt que de lever une exception)
  • renvoie trueuniquement si pathinclut le volume

Dans des scénarios comme celui proposé par le PO, il peut donc être plus approprié que les conditions des réponses précédentes. Contrairement à la condition ci-dessus:

  • path == System.IO.Path.GetFullPath(path)lève des exceptions plutôt que de revenir falsedans ces scénarios:
    • L'appelant n'a pas les autorisations requises
    • Le système n'a pas pu récupérer le chemin absolu
    • le chemin contient un signe deux-points (":") qui ne fait pas partie d'un identificateur de volume
    • Le chemin d'accès spécifié, le nom de fichier ou les deux dépassent la longueur maximale définie par le système
  • System.IO.Path.IsPathRooted(path)renvoie truesi pathcommence par un seul séparateur de répertoire.

Enfin, voici une méthode qui englobe la condition ci-dessus et exclut également les exceptions possibles 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);
}

EDIT: EM0 a fait un bon commentaire et une réponse alternative abordant le cas curieux des chemins comme C:et C:dir. Pour vous aider à décider de la manière dont vous souhaitez gérer ces chemins, vous voudrez peut-être vous plonger dans MSDN -> Applications de bureau Windows -> Développer -> Technologies de bureau -> Accès aux données et stockage -> Systèmes de fichiers locaux - -> Gestion des fichiers -> À propos de la gestion des fichiers -> Création, suppression et maintenance de fichiers -> Nommer des fichiers, des chemins et des espaces de noms -> Chemins complets ou relatifs

Pour les fonctions d'API Windows qui manipulent des fichiers, les noms de fichiers peuvent souvent être relatifs au répertoire en cours, tandis que certaines API nécessitent un chemin complet. Un nom de fichier est relatif au répertoire actuel s'il ne commence pas par l'un des éléments suivants:

  • Un nom UNC de n'importe quel format, qui commence toujours par deux barres obliques inversées ("\"). Pour plus d'informations, consultez la section suivante.
  • Un indicateur de disque avec une barre oblique inverse, par exemple "C: \" ou "d: \".
  • Une seule barre oblique inverse, par exemple, "\ directory" ou "\ file.txt". Ceci est également appelé chemin absolu.

Si un nom de fichier commence par un seul identificateur de disque mais pas par la barre oblique inverse après les deux points, il est interprété comme un chemin relatif vers le répertoire actuel sur le lecteur avec la lettre spécifiée. Notez que le répertoire en cours peut ou non être le répertoire racine en fonction de ce qu'il a été défini lors de la dernière opération de «changement de répertoire» sur ce disque. Des exemples de ce format sont les suivants:

  • «C: tmp.txt» fait référence à un fichier nommé «tmp.txt» dans le répertoire en cours sur le lecteur C.
  • «C: tempdir \ tmp.txt» fait référence à un fichier dans un sous-répertoire du répertoire actuel sur le lecteur C.

[...]

seuil
la source
3
J'aime le fait que cela ne lance pas pour les chemins invalides, mais il retourne true pour les chemins comme "C:" et "C: dir", qui sont résolus par GetFullPath en utilisant le répertoire courant (ils ne sont donc pas absolus). Publié une réponse qui renvoie faux pour ceux-ci.
EM0
@ EM0 - Merci! Vous venez de m'apprendre quelque chose. :)
weir
15

Essayer

System.IO.Path.IsPathRooted(template)

Fonctionne aussi bien pour les chemins UNC que pour les chemins locaux.

Par exemple

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

Ancienne question, mais une autre réponse applicable. Si vous devez vous assurer que le volume est inclus dans un chemin local, vous pouvez utiliser System.IO.Path.GetFullPath () comme ceci:

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
la source
3
C'était ce dont j'avais besoin, et cela semble plus proche de la question initiale puisque IsPathRooted 'renvoie vrai pour les chemins relatifs (pas nécessairement les chemins absolus)
bitcoder
GetFullPathaccède au système de fichiers et peut lever un certain nombre d'exceptions possibles. Voir ma réponse ( stackoverflow.com/a/35046453/704808 ) pour une alternative qui assure toujours un chemin complet.
déversoir le
11

Construire sur déversoir de réponse « : cela ne jette pas pour les chemins invalides, mais aussi des retours falsepour les chemins comme « C: », « C: dirname » et « \ chemin ».

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
}

Notez que cela renvoie des résultats différents sous Windows et Linux, par exemple "/ path" est absolu sous Linux, mais pas sous Windows.

Test de l'unité:

[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
la source
Bon produit. J'ai remarqué que msdn.microsoft.com/en-us/library/windows/desktop/… indique que sous Windows, un chemin n'est pas relatif s'il commence par 'Une seule barre oblique inverse, par exemple, "\ directory" ou "\ file .SMS". Ceci est également appelé un chemin absolu ».
déversoir
1
Bon point! Il semble que ma terminologie soit erronée. Quand j'ai dit "chemin absolu", je pensais vraiment à ce que MS appelle un "chemin complet". J'ai changé le nom et ajouté un cas de test pour cela.
EM0
1
Merci pour cette réponse, cela m'a beaucoup aidé. Cependant, notez que pour un chemin UNC tel que \\ serveur \, la méthode renvoie true, mais cela lèvera une exception si vous appelez ensuite Directory.Exists (path) (System.ArgumentException: 'Le chemin UNC doit être de la forme \\ serveur \ partage. ')
Carl
2
Ravi de voir les gens utiliser toujours ceci et de trouver de nouveaux cas de bord @Carl a mis à jour le code et testez cela!
EM0
6

Pour vérifier si un chemin est pleinement qualifié (MSDN) :

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

C'est un peu plus simple que ce qui a déjà été proposé, et il renvoie toujours false pour les chemins relatifs aux lecteurs comme C:foo. Sa logique est basée directement sur la définition MSDN de «pleinement qualifié», et je n'ai trouvé aucun exemple sur lequel il se comporte mal.


Fait intéressant cependant, .NET Core 2.1 semble avoir une nouvelle méthode Path.IsPathFullyQualifiedqui utilise une méthode internePathInternal.IsPartiallyQualified (emplacement du lien précis à partir du 17/04/2018).

Pour la postérité et une meilleure maîtrise de soi de cet article, voici la mise en œuvre de ce dernier pour référence:

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]));
}
William
la source
4

C'est la solution que j'utilise

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

Cela fonctionne de la manière suivante:

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
la source
Très intéressant! Il est fragile, par exemple, doit correspondre aux types de barres obliques, mais cela est prometteur.
Nicholas Petersen
Il renvoie de mauvais résultats pour les chemins suivants: C:\foo\..\fooouC:\foo\.\.\.
sergtk
1

Appelez la fonction suivante:

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

MSDN doc: méthode Path.IsPathFullyQualified

La citation utile de MSDN doc suit:

Cette méthode gère les chemins qui utilisent le séparateur de répertoire alternatif. C'est une erreur fréquente de supposer que les chemins enracinés ( IsPathRooted (String) ) ne sont pas relatifs. Par exemple, "C: a" est relatif au lecteur, c'est-à-dire qu'il est résolu par rapport au répertoire courant pour C: (enraciné, mais relatif). "C: \ a" est rooté et non relatif, c'est-à-dire que le répertoire courant n'est pas utilisé pour modifier le chemin.

sergtk
la source
0

Je ne suis pas vraiment sûr de ce que vous entendez par chemin complet (bien qu'en supposant à partir de l'exemple que vous vouliez dire non relatif à partir de la racine), eh bien, vous pouvez utiliser la classe Path pour vous aider à travailler avec des chemins de système de fichiers physiques, ce qui devrait couvrir vous pour la plupart des éventualités.

Grant Thomas
la source