103

How do I convert a relative path to an absolute path in a Windows application?

I know we can use server.MapPath() in ASP.NET. But what can we do in a Windows application?

I mean, if there is a .NET built-in function that can handle that...

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Amit Dhall
  • 1,255
  • 4
  • 15
  • 19
  • 2
    Do you mean a relative path to the current directory, in other words the working directory, or relative to the location of the .exe? – Tobias Hertkorn Sep 09 '09 at 11:16
  • 2
    There are two kinds of relative paths. One if of the form "A\B\C" and doesn't imply a particular base. The other has the form ".\A\B" or "..\A\B"; those are relative to the current working directory. – MSalters Sep 09 '09 at 11:18

5 Answers5

204

Have you tried:

string absolute = Path.GetFullPath(relative);

? Note that that will use the current working directory of the process, not the directory containing the executable. If that doesn't help, please clarify your question.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 5
    Would that not be depending on where you start the app from, not depending on where the exe is situated? Granted the question is not really clear on that. – Tobias Hertkorn Sep 09 '09 at 11:15
  • 1
    As you say, the question is not clear. GetFullPath will resolve from the current working directory. I'll edit my response to indicate this. – Jon Skeet Sep 09 '09 at 11:44
  • 1
    If an application is started via Windows Explorer it seems that the current directory and the executing assembly directory are the same (at least until something is done to make them different). This is true even if you use a short-cut to the executable where the short-cut resides somewhere completely different. – H2ONaCl Mar 16 '15 at 09:06
20

If you want to get the path relative to your .exe then use

string absolute = Path.Combine(Application.ExecutablePath, relative);
Tobias Hertkorn
  • 2,742
  • 1
  • 21
  • 28
  • 4
    Just be careful with Path.Combine. If the 'relative' part starts with a slash, it may not do what you think it would. – Noon Silk Sep 09 '09 at 11:52
  • 2
    @silky: well, then it isn't relative, is it? – Tor Haugen Sep 09 '09 at 13:27
  • 1
    Seems `Path.Combine` can't even handle drive-relative paths. It just ignores the initial path it seems. I'm posting my own full solution. – Nyerguds Feb 05 '16 at 07:27
  • 3
    This can't handle a relative path. It only accepts a directory and a filename. If the second argument starts with anything like `..`, it will produce garbage. – Jonathan Wood Sep 21 '18 at 04:06
  • 1
    @JonathanWood Actually, that "garbage" (paths that include `..` in them) is perfectly accepted and resolved by all file manipulation systems in .Net. If it bothers you, execute `absolute = Path.GetFullPath(absolute)` on it. – Nyerguds Sep 30 '19 at 09:52
  • @JonathanWood I just tested your claim. Combined with `..\test\hello.txt` and got `"E:\TestApp\bin\x86\Debug\..\test\hello.txt`. Exactly as expected. No garbage. – Nyerguds Oct 01 '19 at 06:44
  • **Warning:** The result can be something like that: `C:\aa\bb\cc\dd\..\..\..\xxx\zzz\file.txt` with **"..\"** included. Nevertheless such a path can be valide for .NET. When you check with `File.Exists()`, you can get _true_. – Beauty Jun 17 '20 at 06:46
17

This one works for paths on different drives, for drive-relative paths and for actual relative paths. Heck, it even works if the basePath isn't actually absolute; it always uses the current working directory as final fallback.

public static String GetAbsolutePath(String path)
{
    return GetAbsolutePath(null, path);
}

public static String GetAbsolutePath(String basePath, String path)
{
    if (path == null)
        return null;
    if (basePath == null)
        basePath = Path.GetFullPath("."); // quick way of getting current working directory
    else
        basePath = GetAbsolutePath(null, basePath); // to be REALLY sure ;)
    String finalPath;
    // specific for windows paths starting on \ - they need the drive added to them.
    // I constructed this piece like this for possible Mono support.
    if (!Path.IsPathRooted(path) || "\\".Equals(Path.GetPathRoot(path)))
    {
        if (path.StartsWith(Path.DirectorySeparatorChar.ToString()))
            finalPath = Path.Combine(Path.GetPathRoot(basePath), path.TrimStart(Path.DirectorySeparatorChar));
        else
            finalPath = Path.Combine(basePath, path);
    }
    else
        finalPath = path;
    // resolves any internal "..\" to get the true full path.
    return Path.GetFullPath(finalPath);
}
Nyerguds
  • 5,360
  • 1
  • 31
  • 63
  • 1
    Great solution because it combines either absolute or relatives path according to a base path. In my opinion, relativePath argument should be renamed to AbsoluteOrRelativePath, since it is what it really represents. Thanks – Julio Nobre Nov 18 '16 at 13:00
  • 1
    Well, if it's already an absolute path, that's just a special case, really... the function is still meant to resolve relative paths, lol. I just named it that here to make it clear which parameter is which ;) – Nyerguds Nov 18 '16 at 16:21
  • 1
    @JulioNobre especially since the args here are reversed compared to `Path.Combine`. That's easily fixed, but I avoid it since I often use it to resolve relative paths on the working directory, and giving null as first arg looks weird. – Nyerguds Nov 24 '16 at 22:11
  • 1
    I appreciate your advice, but I only intent to use this helper when I need to combine a base path with another path that may be either relative to that base path or absolute. That's why I have preferred to adopt the following signature: GetAbsolutePath(String BasePath, String RelativeOrAbsolutePath). If some argument is null, an exception is raised to reinforce that both are mandatory to use this method. Again, thanks :-) – Julio Nobre Nov 24 '16 at 23:59
  • 2
    Yeah, that's sensible. Can't be bothered to edit this just to juggle some args around though. – Nyerguds Nov 25 '16 at 00:05
  • Ended up doing it anyway, and added overload. I always envisioned `basePath` as optional parameter, hence why it's at the end, but if it's indeed optional, it makes more sense to have it at the start when it's there, to match `Path.Combine()`. – Nyerguds Jun 14 '18 at 10:09
  • This doesn't work for file paths. `C:\TEMP\TEST1.TXT` and a relative path of `..\TEMP2\TEST2.TXT` which I would expect to resolve to `C:\TEMP2\TEST2.TXT` actually resolves to `C:\TEMP\TEMP2\TEST2.TXT` – Adam Plocher Aug 06 '18 at 00:34
  • The problem is it doesn't know that TEST1.TXT isn't a folder I guess... – Adam Plocher Aug 06 '18 at 00:36
  • @AdamPlocher `basePath` is supposed to be a directory, yes. If you use `Path.Combine` it _also_ won't automatically cut off a filename from the first part. If you have a _file_ path, just use `Path.GetDirectoryName` on it first. And if you don't know if it's a file or folder, `System.IO` has functions for that. – Nyerguds Aug 06 '18 at 20:22
1

It's a bit older topic, but it might be useful for someone. I have solved a similar problem, but in my case, the path was not at the beginning of the text.

So here is my solution:

public static class StringExtension
{
    private const string parentSymbol = "..\\";
    private const string absoluteSymbol = ".\\";
    public static String AbsolutePath(this string relativePath)
    {
        string replacePath = AppDomain.CurrentDomain.BaseDirectory;
        int parentStart = relativePath.IndexOf(parentSymbol);
        int absoluteStart = relativePath.IndexOf(absoluteSymbol);
        if (parentStart >= 0)
        {
            int parentLength = 0;
            while (relativePath.Substring(parentStart + parentLength).Contains(parentSymbol))
            {
                replacePath = new DirectoryInfo(replacePath).Parent.FullName;
                parentLength = parentLength + parentSymbol.Length;
            };
            relativePath = relativePath.Replace(relativePath.Substring(parentStart, parentLength), string.Format("{0}\\", replacePath));
        }
        else if (absoluteStart >= 0)
        {
            relativePath = relativePath.Replace(".\\", replacePath);
        }
        return relativePath;
    }
}

Example:

Data Source=.\Data\Data.sdf;Persist Security Info=False;
Data Source=..\..\bin\Debug\Data\Data.sdf;Persist Security Info=False;
vesi
  • 53
  • 1
  • 4
  • 1
    Um. You're reinventing the wheel. `Path.GetFullPath` resolves .\ and ..\ automatically. Also, you're adding the `AbsolutePath` extension function to String class in general... may be a bit overkill. – Nyerguds Jun 14 '18 at 10:05
  • 1
    Am I wrong saying that Path.GetFullPath always considers the base directory as the current directory of the AppDomain of the application. In this case, Path.GetFullPath is not able to return the full path from a different directory. The following algorithm, however, takes this into consideration... I mean, you just have to add another optional parameter which would be a replacing of the CurrentDomainDirectory. – Samuel Jun 29 '18 at 13:52
0

windows 10 python 3.8 type object 'Path' has no attribute 'GetFullPath'

Nick
  • 97
  • 10