Generating a relative path in C#
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/
.