// 2009.03.13 一歩二歩散歩
// 2つの絶対パスから相対パスを取得する。
using System;
using System.Text;
public static class PathUtil
{
///
/// 絶対パスから相対パスを取得します。
///
/// 基準となる絶対パス
/// 相対パスへと変換する絶対パス
/// 相対パス
public static string GetRelativePath( string from, string dest )
{
if( from == null )
{ throw new ArgumentNullException( "from" ); }
if( dest == null )
{ throw new ArgumentNullException( "dest" ); }
//////////////////////////////
char[] directorySeparator = { System.IO.Path.DirectorySeparatorChar };
//パスを、ディレクトリ名とファイル名の配列に分割する。
//配列の最後尾にファイル名が格納されている。
//"C:\\"などとした場合は、{ "C:", "" } と分割され、ファイル名はstring.Emptyになる。
string[] fromDirectories = from.Split( directorySeparator, StringSplitOptions.None );
string[] destDirectories = dest.Split( directorySeparator, StringSplitOptions.None );
// ・・・わざわざSplit()でstring[]型に分割しなくてもできそうな気がするけど、
// ま、とりあえず、という事で。
//絶対パスは最低でも、"「ルートディレクトリ(ドライブ)」\「ファイル名」" となるので、
//Lenthは2以上になるはず。
if( fromDirectories.Length < 2 )
{ throw new ArgumentException( "Value is not Absolute path.", "from" ); }
if( destDirectories.Length < 2 )
{ throw new ArgumentException( "Value is not Absolute path.", "dest" ); }
//////////////////////////////
//ドライブ名が異なっている場合。
if( fromDirectories[0] != destDirectories[0] )
{
return dest;
}
//////////////////////////////
//ファイルが置かれているディレクトリ(の名前が格納されている要素)のインデックス
int fromFileDirIndex = fromDirectories.Length - 2;
int destFileDirIndex = destDirectories.Length - 2;
//2つのパスで共通なディレクトリ(の名前が格納されている要素)のインデックス
//ここでいう「共通なディレクトリ」というのは、例えば、
// C: \ dir \ dir2 \ hoge.txt
// C: \ dir \ asdf \ foo.txt
//の、「dir」ディレクトリのこと。
int commonDirIndex = 0;
//共通なディレクトリを探す。
int length = ( fromFileDirIndex < destFileDirIndex ) ? fromFileDirIndex : destFileDirIndex; //どっちか小さい方
for( int dirIndex = 1; dirIndex <= length; dirIndex++ )
{
if( fromDirectories[dirIndex] == destDirectories[dirIndex] )
{
commonDirIndex++;
}
else
{
break;
}
}
//相対パス
StringBuilder relativePath = new StringBuilder();
//上のディレクトリに移動する回数
int upDirCount = fromFileDirIndex - commonDirIndex;
for( int i = 0; i < upDirCount; i++ )
{
// 上の階層のディレクトリに移動する分だけ「..\」を付け足す。
relativePath.Append( ".." );
relativePath.Append( directorySeparator[0] );
}
for( int dirIndex = commonDirIndex + 1; dirIndex <= destFileDirIndex; dirIndex++ )
{
//共通なディレクトリ以降のディレクトリ名を付け足していく。
relativePath.Append( destDirectories[dirIndex] );
relativePath.Append( directorySeparator[0] );
}
//最後にファイル名を付け足して完了。
relativePath.Append( destDirectories[destDirectories.Length - 1] );
return relativePath.ToString();
}
}