// 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(); } }