27

For example, how can I make this

"C:\RootFolder\SubFolder\MoreSubFolder\LastFolder\SomeFile.txt"

relative to this folder

"C:\RootFolder\SubFolder\"

if the expected result is

"MoreSubFolder\LastFolder\SomeFile.txt"
  • Wouldn't the expected result be "MoreSubFolder\LastFolder\SomeFile.txt"? – Chris Shain Jan 28 '12 at 04:19
  • Yup thanks for pointing out my mistake! –  Jan 28 '12 at 04:23
  • You need to rephrase this. I read it twice, and I'm still not sure what you want really. Otherwise, I'm tempted to answer: use IndexOf and Substring methods to get the 2nd part of the path (or to remove the 1st part of the path) - and I have the feeling that's not what you want. Look into static methods of System.IO.Path class - it's got a few nice helpers for combining paths, and similar. –  Jan 28 '12 at 04:30
  • 1
    It is what I want. However, I would have preferred avoiding string manipulations. A built-in framework way would be better, if possible. –  Jan 28 '12 at 04:35
  • Does this answer your question? [How to get relative path from absolute path](https://stackoverflow.com/questions/275689/how-to-get-relative-path-from-absolute-path) – Kelly Elton Sep 04 '20 at 01:44

3 Answers3

45

Yes, you can do that, it's easy, think of your paths as URIs:

Uri fullPath = new Uri(@"C:\RootFolder\SubFolder\MoreSubFolder\LastFolder\SomeFile.txt", UriKind.Absolute);
Uri relRoot = new Uri(@"C:\RootFolder\SubFolder\", UriKind.Absolute);

string relPath = relRoot.MakeRelativeUri(fullPath).ToString();
// relPath == @"MoreSubFolder\LastFolder\SomeFile.txt"
ordag
  • 2,401
  • 4
  • 25
  • 35
15

In your example, it's simply absPath.Substring(relativeTo.Length).

More elaborate example would require going back a few levels from the relativeTo, as follows:

"C:\RootFolder\SubFolder\MoreSubFolder\LastFolder\SomeFile.txt"
"C:\RootFolder\SubFolder\Sibling\Child\"

The algorithm to make a relative path would look as follows:

  • Remove the longest common prefix (in this case, it is "C:\RootFolder\SubFolder\")
  • Count the number of folders in relativeTo (in this case, it is 2: "Sibling\Child\")
  • Insert ..\ for each remaining folder
  • Concatenate with the remainder of the absolute path after the suffix removal

The end result looks like this:

"..\..\MoreSubFolder\LastFolder\SomeFile.txt"
Sergey Kalinichenko
  • 697,062
  • 78
  • 1,055
  • 1,465
0

Here is my 5-cents without using any special Url class for that purpose.

Search for makeRelative in following git repository: https://github.com/tapika/syncProj/blob/8ea41ebc11f538a22ed7cfaf59a8b7e0b4c3da37/syncProj.cs#L1685

(Fixed version frozen once upon a time, search latest version separately)

I'll fix bugs if there is any.

Here is copy of same code as in link above:

/// <summary>
/// Rebases file with path fromPath to folder with baseDir.
/// </summary>
/// <param name="_fromPath">Full file path (absolute)</param>
/// <param name="_baseDir">Full base directory path (absolute)</param>
/// <returns>Relative path to file in respect of baseDir</returns>
static public String makeRelative(String _fromPath, String _baseDir)
{
    String pathSep = "\\";
    String fromPath = Path.GetFullPath(_fromPath);
    String baseDir = Path.GetFullPath(_baseDir);            // If folder contains upper folder references, they gets lost here. "c:\test\..\test2" => "c:\test2"

    String[] p1 = Regex.Split(fromPath, "[\\\\/]").Where(x => x.Length != 0).ToArray();
    String[] p2 = Regex.Split(baseDir, "[\\\\/]").Where(x => x.Length != 0).ToArray();
    int i = 0;

    for (; i < p1.Length && i < p2.Length; i++)
        if (String.Compare(p1[i], p2[i], true) != 0)    // Case insensitive match
            break;

    if (i == 0)     // Cannot make relative path, for example if resides on different drive
        return fromPath;

    String r = String.Join(pathSep, Enumerable.Repeat("..", p2.Length - i).Concat(p1.Skip(i).Take(p1.Length - i)));
    return r;
}
TarmoPikaro
  • 3,886
  • 1
  • 38
  • 52
  • Sorry, but this does not seem to work `makeRelative(@"F:\a\b", @"F:\")` for example returns `..\b` (instead of `a\b`) – Mikescher Mar 01 '17 at 14:23
  • Can you try again - I have updated my latest version ? If it does not work, I'll fix it. – TarmoPikaro Mar 01 '17 at 16:05
  • Provide full code, do not make link answer only. The code has changed and your link points to another part of the code. – xmedeko Mar 22 '19 at 18:00