Path.Combine absolu avec des chaînes de chemin relatives

94

J'essaie de rejoindre un chemin Windows avec un chemin relatif en utilisant Path.Combine.

Cependant, Path.Combine(@"C:\blah",@"..\bling")renvoie C:\blah\..\blingau lieu de C:\bling\.

Est-ce que quelqu'un sait comment accomplir cela sans écrire mon propre résolveur de chemin relatif (ce qui ne devrait pas être trop difficile)?

CVertex
la source
5
Nous obtenons des réponses différentes ici ... Je ne pense pas que ce soit un doublon
CVertex
1
c'est en double, même si je pense que Path.GetFullName est une meilleure solution.
Greg Dean
Vous venez de vous contredire. Mais merci pour la réponse alternative.
CVertex
duplication possible de Path.Combine et la notation par points
Julien Bérubé

Réponses:

63

Ce qui fonctionne:

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

(résultat: chemin absolu = "C: \ bling.txt")

Ce qui ne marche pas

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

(résultat: chemin absolu = "C: /blah/bling.txt")

Llyle
la source
8
Oui, c'est ce que
j'insinue
7
Assurez-vous simplement que baseDirectory a le \\ de fin, sinon vous vous retrouvez avec C:\\blah..\\bling.txtet cela ne fonctionne pas. Dans ce cas, vous pouvez les ajouter manuellement à la chaîne ou fairePath.GetFullPath(Path.Combine(baseDirectory, relativePath))
Nelson Rothermel
5
Le résultat de votre section What Works ne devrait-il pas être C:\bling.txt?
cod3monk3y
Pourquoi la méthode basée sur URI ne fonctionne-t-elle pas? Selon cette réponse , le résultat est valide (et il semble également être reconnu sur Windows ).
FH
37

Appelez Path.GetFullPath sur le chemin combiné http://msdn.microsoft.com/en-us/library/system.io.path.getfullpath.aspx

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

(Je suis d'accord que Path.Combine devrait le faire par lui-même)

Colonel Panic
la source
Notez que cela ne fonctionne que si le premier chemin est un chemin absolu. Ça ne marche pas pourPath.GetFullPath(Path.Combine(@"..\..\blah",@"\bling"))
derekantrican
16

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

shahkalpesh
la source
2
Remarque: devrait aboutir àc:\windows\system32
cod3monk3y
4

Pour les applications universelles Windows Path.GetFullPath()ne sont pas disponibles, vous pouvez utiliser la System.Uriclasse à la place:

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

Cela vous donnera exactement ce dont vous avez besoin (le chemin ne doit PAS exister pour que cela fonctionne)

DirectoryInfo di = new DirectoryInfo(@"C:\blah\..\bling");
string cleanPath = di.FullName;
Jonathan Mc Namee
la source
1
Path.GetFullPath () et DirectoryInfo.FullName fonctionneront sur un chemin fictif. Le problème est que lorsque le fichier existe réellement, le processus d'exécution a besoin de FileIOPermission - vrai pour les deux API. (voir MSDN)
Paul Williams
1

Faites attention aux backslashes, ne les oubliez pas (ne les utilisez pas deux fois :)

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
la source
0

Path.GetFullPath() ne fonctionne pas avec les chemins relatifs.

Voici la solution qui fonctionne avec les deux chemins relatifs + absolus. Il fonctionne à la fois sous Linux + Windows et il garde le ..comme prévu au début du texte (au repos, ils seront normalisés). La solution repose toujours sur Path.GetFullPathle correctif avec une petite solution de contournement.

C'est une méthode d'extension alors utilisez-la comme 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
la source