iandevlin.com

Icon

A mixture of musings on web design & development, history, and life

Generating a relative path in C#

c# dot net logo

Today I was looking for a way to find a relative path between one absolute directory and another in C#. The .NET libraries themselves don’t seem to have anything that helps with this so I performed the obligatory Google search and came across a handy little function written by Peter Morris which I’ve now incorporated in my library.

I’ve reproduced the code here with some minor changes (aesthetic and personal preference code layout ones), but the work is Peter’s:

public string RelativePath(string absPath, string relTo) {
  string[] absDirs = absPath.Split('\\');
  string[] relDirs = relTo.Split('\\');
  
  // Get the shortest of the two paths
  int len = absDirs.Length < relDirs.Length ? absDirs.Length : 
  relDirs.Length;

  // Use to determine where in the loop we exited
  int lastCommonRoot = -1;
  int index;

  // Find common root
  for (index = 0; index < len; index++) {
    if (absDirs[index] == relDirs[index]) lastCommonRoot = index;
    else break;
  }

  // If we didn't find a common prefix then throw
  if (lastCommonRoot == -1) {
    throw new ArgumentException("Paths do not have a common base");
  }

  // Build up the relative path
  StringBuilder relativePath = new StringBuilder();

  // Add on the ..
  for (index = lastCommonRoot + 1; index < absDirs.Length; index++) {
    if (absDirs[index].Length > 0) relativePath.Append("..\\");
  }
  
  // Add on the folders
  for (index = lastCommonRoot + 1; index < relDirs.Length - 1; index++) {
    relativePath.Append(relDirs[index] + "\\");
  }
  relativePath.Append(relDirs[relDirs.Length - 1]);
  
return relativePath.ToString();
}

Update

As you can see from a comment below, which was also added to Peter’s site, this does not already exist in the framework in the form of Path.Combine(pathToRelate, absolutePath)

Here’s an example.

If:

pathToRelate = "C:\Inetpub\wwwroot\Project1\Master\Dev\SubDir1";
absolutePath = "C:\Inetpub\wwwroot\Project1\Master\Dev\SubDir2\SubDirIWant";

then using Path.Combine(pathToRelate, absolutePath) returns: C:\Inetpub\wwwroot\Project1\Master\Dev\ which is not the same as what RelativePath(string absPath, string relTo) returns which is ../SubDir2/SubDirIWant/.

6 Responses

  1. did you miss the comments at peters’s site?

    string relativePath = Path.Combine(pathToRelate, absolutePath)

    (already in the framework)

  2. ian says:

    Hi Caspar, no I didn’t miss the comments on Peter’s site and Path.Combine does not return the same result.

    e.g.

    pathToRelate = "C:\Inetpub\wwwroot\Project1\Master\Dev\SubDir1";
    absolutePath = "C:\Inetpub\wwwroot\Project1\Master\Dev\SubDir2\SubDirIWant";

    Using Path.Combine() returns: C:\Inetpub\wwwroot\Project1\Master\Dev\ which is not what I want. I want the path as it is relative to the absolutePath. Running this through Peter’s function returns: ../SubDir2/SubDirIWant/ which is what I want.

    I will amend the post to point this out.

  3. cieszak says:

    Hi, I found some typo in this code:
    can you fix it (for future users :) )?
    absePath => absPath
    relaDirs => relDirs
    length => len

  4. ian says:

    Ah, thanks for pointing them out cieszak, fixed as requested!

  5. Marco Wagner says:

    exactly what i was looking for!

    thanks for that, ian!

    marco

  6. ian says:

    You’re welcome Marco, glad to be of assistance!

Leave a Reply