Path.Combine absoluto com strings de caminho relativo

94

Estou tentando juntar um caminho do Windows com um caminho relativo usando Path.Combine.

No entanto, Path.Combine(@"C:\blah",@"..\bling")retorna em C:\blah\..\blingvez de C:\bling\.

Alguém sabe como fazer isso sem escrever meu próprio resolvedor de caminho relativo (o que não deve ser muito difícil)?

CVertex
fonte
5
Estamos recebendo respostas diferentes aqui .. Não acho que seja uma duplicata
CVertex
1
é duplicado, embora eu ache que Path.GetFullName é uma solução melhor.
Greg Dean,
Você apenas se contradisse. Mas obrigado pela resposta alternativa.
CVertex
possível duplicata de Path.Combine e a notação de ponto
Julien Bérubé

Respostas:

63

O que funciona:

string relativePath = "..\\bling.txt";
string baseDirectory = "C:\\blah\\";
string absolutePath = Path.GetFullPath(baseDirectory + relativePath);

(resultado: absolutePath = "C: \ bling.txt")

O que não funciona

string relativePath = "..\\bling.txt";
Uri baseAbsoluteUri = new Uri("C:\\blah\\");
string absolutePath = new Uri(baseAbsoluteUri, relativePath).AbsolutePath;

(resultado: absolutePath = "C: /blah/bling.txt")

Llyle
fonte
8
Sim, é isso que estou insinuando com o post
Llyle
7
Apenas certifique-se de que baseDirectory tenha o \\ final, caso contrário, você terminará com C:\\blah..\\bling.txte isso não funcionará. Nesse caso, você pode adicioná-los manualmente à string ou fazerPath.GetFullPath(Path.Combine(baseDirectory, relativePath))
Nelson Rothermel
5
Não deveria ser o resultado de sua seção O que funcionaC:\bling.txt ?
cod3monk3y
Por que o método baseado em URI não funciona? De acordo com esta resposta , o resultado é válido (e parece ser reconhecido no Windows também ).
FH
37

Chame Path.GetFullPath no caminho combinado http://msdn.microsoft.com/en-us/library/system.io.path.getfullpath.aspx

> Path.GetFullPath(Path.Combine(@"C:\blah\",@"..\bling"))
C:\bling

(Eu concordo que o Path.Combine deve fazer isso sozinho)

Coronel Panic
fonte
Observe que isso só funciona se o primeiro caminho for um caminho absoluto. Não funciona paraPath.GetFullPath(Path.Combine(@"..\..\blah",@"\bling"))
derekantrican
16

Path.GetFullPath(@"c:\windows\temp\..\system32")?

Shahkalpesh
fonte
2
Observação: deve resultar emc:\windows\system32
cod3monk3y
4

Para aplicativos universais do Windows Path.GetFullPath()não disponíveis, você pode usar a System.Uriclasse em seu lugar:

 Uri uri = new Uri(Path.Combine(@"C:\blah\",@"..\bling"));
 Console.WriteLine(uri.LocalPath);
thumbmunkeys
fonte
3

Isso lhe dará exatamente o que você precisa (o caminho NÃO precisa existir para que funcione)

DirectoryInfo di = new DirectoryInfo(@"C:\blah\..\bling");
string cleanPath = di.FullName;
Jonathan Mc Namee
fonte
1
Tanto Path.GetFullPath () quanto DirectoryInfo.FullName funcionarão em um caminho fictício. O problema é que, quando o arquivo realmente existe, o processo de execução precisa de FileIOPermission - verdadeiro para ambas as APIs. (veja MSDN)
Paul Williams de
1

Tenha cuidado com as barras invertidas, não se esqueça delas (nem use duas vezes :)

string relativePath = "..\\bling.txt";
string baseDirectory = "C:\\blah\\";
//OR:
//string relativePath = "\\..\\bling.txt";
//string baseDirectory = "C:\\blah";
//THEN
string absolutePath = Path.GetFullPath(baseDirectory + relativePath);
Zaknafein
fonte
0

Path.GetFullPath() não funciona com caminhos relativos.

Esta é a solução que funciona com caminhos relativos + absolutos. Funciona tanto em Linux + Windows e mantém ..como esperado no início do texto (em repouso eles serão normalizados). A solução ainda depende Path.GetFullPathde fazer a correção com uma pequena solução alternativa.

É um método de extensão, então use-o como text.Canonicalize()

/// <summary>
///     Fixes "../.." etc
/// </summary>
public static string Canonicalize(this string path)
{
    if (path.IsAbsolutePath())
        return Path.GetFullPath(path);
    var fakeRoot = Environment.CurrentDirectory; // Gives us a cross platform full path
    var combined = Path.Combine(fakeRoot, path);
    combined = Path.GetFullPath(combined);
    return combined.RelativeTo(fakeRoot);
}
private static bool IsAbsolutePath(this string path)
{
    if (path == null) throw new ArgumentNullException(nameof(path));
    return
        Path.IsPathRooted(path)
        && !Path.GetPathRoot(path).Equals(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)
        && !Path.GetPathRoot(path).Equals(Path.AltDirectorySeparatorChar.ToString(), StringComparison.Ordinal);
}
private static string RelativeTo(this string filespec, string folder)
{
    var pathUri = new Uri(filespec);
    // Folders must end in a slash
    if (!folder.EndsWith(Path.DirectorySeparatorChar.ToString())) folder += Path.DirectorySeparatorChar;
    var folderUri = new Uri(folder);
    return Uri.UnescapeDataString(folderUri.MakeRelativeUri(pathUri).ToString()
        .Replace('/', Path.DirectorySeparatorChar));
}
U. Bulle
fonte