tags:

views:

886

answers:

2

I'm writing a console utility to do some processing on files specified on the commandline, but I've run into a problem I can't solve through Google/SO. If a full path, including drive letter, is specified, how do I reformat that path to be relative to the current working directory?

There must be something similar to the VirtualPathUtility.MakeRelative function, but if there is, it eludes me.

+4  A: 

You can use Environment.CurrentDirectory to get the current directory, and FileSystemInfo.FullPath to get the full path to any location. So, fully qualify both the current directory and the file in question, and then check whether the full file name starts with the directory name - if it does, just take the appropriate substring based on the directory name's length.

Here's some sample code:

using System;
using System.IO;

class Program
{
    public static void Main(string[] args)
    {
        string currentDir = Environment.CurrentDirectory;
        DirectoryInfo directory = new DirectoryInfo(currentDir);
        FileInfo file = new FileInfo(args[0]);

        string fullDirectory = directory.FullName;
        string fullFile = file.FullName;

        if (!fullFile.StartsWith(fullDirectory))
        {
            Console.WriteLine("Unable to make relative path");
        }
        else
        {
            // The +1 is to avoid the directory separator
            Console.WriteLine("Relative path: {0}",
                              fullFile.Substring(fullDirectory.Length+1));
        }
    }
}

I'm not saying it's the most robust thing in the world (symlinks could probably confuse it) but it's probably okay if this is just a tool you'll be using occasionally.

Jon Skeet
Well, it doesn't do relative paths that are below the current directory. I imagine that's going to be fun.
Ray
Not sure what you mean: c:\Documents and Settings\Jon Skeet\Test> test.exe "c:\Documents and Settings\Jon Skeet\Test\foo\bar"Relative path: foo\bar
Jon Skeet
In other words, it works for me. Please give a concrete example of what you expect to fail.
Jon Skeet
I mean, getting a relative path for C:\TestDir\OneDirectory from C:\TestDir\AnotherDiectory is not going to return ..\OneDirectory. I'm not saying that it couldn't be changed to do that, it's just not going to be simple.
Ray
Ah, you mean paths that are *above* the current directory. No, that would be a pain. Why do you need a relative path anyway?
Jon Skeet
+4  A: 

If you don't mind the slashes being switched, you could [ab]use Uri:

Uri uri1 = new Uri(@"c:\foo\bar\blop\blap");
Uri uri2 = new Uri(@"c:\foo\bar\");
string relativePath = uri2.MakeRelativeUri(uri1).ToString();
Marc Gravell
Nice! and just adding .Replace('/','\\') makes everything perfect
total