Verifique se o caminho completo foi fornecido

104

Existe um método para verificar se o caminho fornecido é o caminho completo? Agora estou fazendo isso:

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

Mas deve haver uma maneira mais elegante de verificar isso?

hs2d
fonte

Respostas:

141

Tentar usar System.IO.Path.IsPathRooted? Ele também retorna truepara caminhos absolutos.

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
fonte
14
Como o segundo exemplo pode ser o caminho absoluto?
om471987
4
O segundo caminho não é absoluto, mas está enraizado. A barra inicial indica a raiz do sistema.
detaylor
3
@SmirkinGherkin então qual é a diferença entre um caminho enraizado e absoluto?
Jason Axelson,
1
Veja minha resposta ( stackoverflow.com/a/35046453/704808 ) para uma alternativa que garante um caminho completo, mantendo as vantagens de IsPathRooted: evitar acessar o sistema de arquivos ou lançar exceções para entrada inválida.
açude
1
@daniel, IIRC foi incluído para mostrar que o caminho não precisava ser um caminho válido para ser usado IsPathRooted, certamente não era nada significativo. A GetFullPathlinha foi incluída para que o caminho sendo avaliado pudesse ser observado
detaylor
30
Path.IsPathRooted(path)
&& !Path.GetPathRoot(path).Equals(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)

A condição acima:

  • não requer permissões do sistema de arquivos
  • retorna falsena maioria dos casos em que o formato de pathé inválido (em vez de lançar uma exceção)
  • retorna trueapenas se pathinclui o volume

Em cenários como o apresentado pelo OP, pode, portanto, ser mais adequado do que as condições nas respostas anteriores. Ao contrário da condição acima:

  • path == System.IO.Path.GetFullPath(path)lança exceções em vez de retornar falsenestes cenários:
    • O chamador não tem as permissões necessárias
    • O sistema não conseguiu recuperar o caminho absoluto
    • o caminho contém dois pontos (":") que não faz parte de um identificador de volume
    • O caminho especificado, o nome do arquivo ou ambos excedem o comprimento máximo definido pelo sistema
  • System.IO.Path.IsPathRooted(path)retorna truese pathcomeça com um único separador de diretório.

Finalmente, aqui está um método que envolve a condição acima e também exclui as possíveis exceções 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 fez um bom comentário e resposta alternativa abordando o curioso caso de caminhos como C:e C:dir. Para ajudar a decidir como você pode querer lidar com tais caminhos, você pode querer mergulhar fundo no MSDN -> aplicativos de desktop do Windows -> Desenvolver -> Tecnologias de desktop -> Acesso e armazenamento de dados -> Sistemas de arquivos locais - -> Gerenciamento de arquivos -> Sobre gerenciamento de arquivos -> Criação, exclusão e manutenção de arquivos -> Arquivos de nomenclatura, caminhos e namespaces -> Caminhos totalmente qualificados versus caminhos relativos

Para funções da API do Windows que manipulam arquivos, os nomes dos arquivos podem frequentemente ser relativos ao diretório atual, enquanto algumas APIs requerem um caminho totalmente qualificado. Um nome de arquivo é relativo ao diretório atual se não começar com um dos seguintes:

  • Um nome UNC de qualquer formato, que sempre começa com dois caracteres de barra invertida ("\"). Para obter mais informações, consulte a próxima seção.
  • Um designador de disco com uma barra invertida, por exemplo "C: \" ou "d: \".
  • Uma única barra invertida, por exemplo, "\ diretório" ou "\ arquivo.txt". Isso também é conhecido como um caminho absoluto.

Se um nome de arquivo começar apenas com um designador de disco, mas não com a barra invertida após os dois pontos, ele será interpretado como um caminho relativo para o diretório atual na unidade com a letra especificada. Observe que o diretório atual pode ou não ser o diretório raiz, dependendo de como foi definido durante a operação de "alteração de diretório" mais recente nesse disco. Os exemplos deste formato são os seguintes:

  • "C: tmp.txt" refere-se a um arquivo chamado "tmp.txt" no diretório atual da unidade C.
  • "C: tempdir \ tmp.txt" refere-se a um arquivo em um subdiretório do diretório atual na unidade C.

[...]

açude
fonte
3
Eu gosto que isso não lance para caminhos inválidos, mas retorna true para caminhos como "C:" e "C: dir", que são resolvidos por GetFullPath usando o diretório atual (portanto, eles não são absolutos). Postado uma resposta que retorna falso para estes.
EM0
@ EM0 - Obrigado! Você acabou de me ensinar algo. :)
açude
15

Experimentar

System.IO.Path.IsPathRooted(template)

Funciona tanto para caminhos UNC quanto locais.

Por exemplo

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

Pergunta antiga, mas mais uma resposta aplicável. Se você precisa garantir que o volume seja incluído em um caminho local, você pode usar System.IO.Path.GetFullPath () desta forma:

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
fonte
3
Isso era o que eu precisava, e parece mais perto da pergunta original, pois IsPathRooted 'retorna verdadeiro para caminhos relativos (não necessariamente caminhos absolutos)
bitcoder
GetFullPathacessa o sistema de arquivos e pode lançar uma série de exceções possíveis. Veja minha resposta ( stackoverflow.com/a/35046453/704808 ) para uma alternativa que ainda garante um caminho completo.
açude de
11

Com base na resposta do weir : isso não lança para caminhos inválidos, mas também retorna falsepara caminhos como "C:", "C: dirname" e "\ path".

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
}

Observe que isso retorna resultados diferentes no Windows e no Linux, por exemplo, "/ path" é absoluto no Linux, mas não no Windows.

Teste de unidade:

[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
fonte
Coisa boa. Percebi que msdn.microsoft.com/en-us/library/windows/desktop/… afirma que no Windows um caminho não é relativo se começar com 'Uma única barra invertida, por exemplo, "\ diretório" ou "\ arquivo .TXT". Isso também é conhecido como um caminho absoluto. '
açude
1
Bom ponto! Parece que minha terminologia estava errada. Quando eu disse "caminho absoluto", estava realmente pensando no que a MS chama de "caminho completo". Mudei o nome e adicionei um caso de teste para isso.
EM0
1
Obrigado por esta resposta, me ajudou muito. No entanto, observe que para um caminho UNC como \\ servidor \, o método retorna verdadeiro, mas isso lançará uma exceção se você chamar Directory.Exists (path) (System.ArgumentException: 'O caminho UNC deve estar no formato \\ servidor \ compartilhamento. ')
Carl
2
É bom ver as pessoas ainda usando isso e encontrando novos casos extremos @Carl Atualizou o código e teste isso!
EM0
6

Para verificar se um caminho é totalmente qualificado (MSDN) :

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

É um pouco mais simples do que o que já foi proposto e ainda retorna falso para caminhos relativos ao drive como C:foo. Sua lógica é baseada diretamente na definição do MSDN de "totalmente qualificado" e não encontrei nenhum exemplo de mau comportamento.


Curiosamente, no entanto, o .NET Core 2.1 parece ter um novo método Path.IsPathFullyQualifiedque usa um método interno PathInternal.IsPartiallyQualified(localização do link exata em 17/04/2018).

Para a posteridade e melhor autocontenção deste post, aqui está a implementação deste último para referência:

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
fonte
4

Esta é a solução que uso

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

Funciona da seguinte maneira:

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
fonte
Muito interessante! É frágil, por exemplo, tem que corresponder aos tipos de barra, mas isso é promissor.
Nicholas Petersen de
Ele retorna resultados errados para os seguintes caminhos: C:\foo\..\fooouC:\foo\.\.\.
sergtk 05 de
1

Chame a seguinte função:

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

Documento MSDN: Método Path.IsPathFullyQualified

A citação útil do documento MSDN é a seguinte:

Este método lida com caminhos que usam o separador de diretório alternativo. É um erro frequente presumir que os caminhos com raiz ( IsPathRooted (String) ) não são relativos. Por exemplo, "C: a" é relativo à unidade, ou seja, é resolvido em relação ao diretório atual para C: (com raiz, mas relativo). "C: \ a" está enraizado e não é relativo, ou seja, o diretório atual não é usado para modificar o caminho.

sergtk
fonte
0

Não tenho certeza do que você quer dizer com caminho completo (embora, supondo que você queira dizer não relativo a partir da raiz), bem, você pode usar a classe Path para ajudá-lo a trabalhar com caminhos de sistema de arquivos físicos, que devem abranger você para a maioria das eventualidades.

Grant Thomas
fonte