using System;
using System.IO;
class Sample {
// basePathを基準としてpathへの相対パスを取得するメソッド
static string GetRelativePath(string basePath, string path)
{
if (basePath == null)
throw new ArgumentNullException("basePath");
if (path == null)
throw new ArgumentNullException("path");
// 現在Windows上で動作しているかどうか
var isRunningOnWindows = (int)Environment.OSVersion.Platform < 4;
if (isRunningOnWindows && !Path.IsPathRooted(basePath))
throw new ArgumentException("パスは絶対パスである必要があります", "basePath");
// URIとして処理する前にパス中の%をURLエンコードする
basePath = basePath.Replace("%", "%25");
path = path .Replace("%", "%25");
if (!isRunningOnWindows) {
// 非Windows環境ではパスをURIとして解釈させるためにfile://スキームを前置する
basePath = Uri.UriSchemeFile + Uri.SchemeDelimiter + basePath.Replace(":", "%3A");
path = Uri.UriSchemeFile + Uri.SchemeDelimiter + path .Replace(":", "%3A");
}
// パスをURIに変換
var uriBase = new Uri(basePath);
var uriTarget = new Uri(path);
// MakeRelativeUriメソッドで相対パスを取得する
// 同時にURIに変換する際にエスケープされた文字列をアンエスケープする
var relativePath = Uri.UnescapeDataString(uriBase.MakeRelativeUri(uriTarget).ToString());
// ディレクトリ区切り文字を環境に合わせて置換する
relativePath = relativePath.Replace('/', Path.DirectorySeparatorChar);
// URLエンコードした%を元に戻す
return relativePath.Replace("%25", "%");
}
static void Main()
{
var paths = (int)Environment.OSVersion.Platform < 4
? // Windows形式のパス
new[] {
(@"E:\", @"E:\dir"),
(@"E:\", @"E:\dir\"),
(@"E:\", @"E:\dir\file.txt"),
(@"E:\dir", @"E:\"),
(@"E:\dir\", @"E:\"),
(@"E:\dir\file.txt", @"E:\"),
(@"E:\dir-from", @"E:\dir-to"),
(@"E:\dir-from", @"E:\dir-to\file-to.txt"),
(@"E:\dir-from\file-from.txt", @"E:\dir-to\file-to.txt"),
(@"E:\", @"C:\"),
(@"E:\dir-from\file-from.txt", @"C:\dir-to\file-to.txt"),
}
: // UNIX形式のパス
new[] {
(@"/", @"/dir"),
(@"/", @"/dir/"),
(@"/", @"/dir/file.txt"),
(@"/dir", @"/"),
(@"/dir/", @"/"),
(@"/dir/file.txt", @"/"),
(@"/dir-from", @"/dir-to"),
(@"/dir-from", @"/dir-to/file-to.txt"),
(@"/dir-from/file-from.txt", @"/dir-to/file-to.txt"),
};
foreach (var (pathFrom, pathTo) in paths) {
Console.WriteLine($"path from = {pathFrom}");
Console.WriteLine($"path to = {pathTo}");
Console.WriteLine($"relative = {GetRelativePath(pathFrom, pathTo)}");
Console.WriteLine();
}
}
}