[C#・Path]実行 DLL から動的にファイルパスを指定
開発言語として C# を使用して10ヶ月になります。🔟🌻
現在、組み込み系アプリケーションのソリューション開発に携わっています。 Visual Studio を用いて複数のプログラムを作成し、メインプログラム( exe ファイル)から多数の DLL を呼び出して処理を実行します。それぞれの DLL を作成すると単体テストを行い、動作保証を確認します。
今回のアプリケーションでは入力データを受け取るため、テストを実行する際はデータのファイルパスを指定する必要があります。データをフルパスで指定してもよいですが、 PATH クラス を使用することで効率的に指定することができ、汎用的なソースコードになります。🌭
今回は実行 DLL のパスから動的に入力データパスを割り当てる一連の方法をまとめました。議事録を兼ねてつらつらと。。。2022/8/16現在での内容です。
ファイルパスを使用する際の有効的な記載方法
1. @ を先頭につける
string filePath = "C:\\Zenn\\SamplePath\\UnitTest\\UT_input ";
// C:¥Zenn¥SamplePath¥UnitTest¥UT_input
string filePath = @"C:\Zenn\SamplePath\UnitTest\UT_input ";
// C:¥Zenn¥SamplePath¥UnitTest¥UT_input
C# では¥はエスケープ文字となり、特殊文字を表現するため、ディレクトリを指定するには区切りの¥ ⇒ ¥¥と記述する必要があります。
2. Path.Combine メソッドを使用する
Path.Combine メソッドは複数の文字列を1つのパスに結合するメソッドです。手動で¥¥を加えることなくパスを結合することができます。(最大結合数は 4 であり、5 以上は配列で渡します)
今回はフォルダを下記のように定義します。string folderName1 = @"C:/";
string folderName2 = "Zenn";
string folderName3 = "SamplePath";
string folderName4 = "UnitTest";
string folderName5 = "UT_input";
- Path.Combine メソッドを使用しない場合
string path = folderName1 + @"¥" + folderName2 + @"¥" + folderName3 + @"¥" + folderName4 + @"¥" + folderName5;
// C:¥Zenn¥SamplePath¥UnitTest¥UT_input
@
をつけるのか、¥
をつけるのかなどを考慮する必要があります。
- Path.Combine メソッドを使用する場合
string path = Path.Combine(@"C:/Zenn", fileName3, fileName4, fileName5);
// C:¥Zenn¥SamplePath¥UnitTest¥UT_input
パスを指定するだけで¥
をつける必要があるのか内部的に判断してくれます。
主な注意点としては 末尾が¥
、:
、/
で終わる場合は¥
を付けずに結合すること です。C ドライブを指定する場合などは明示的に¥
を記述する必要があります。
詳しくは下記が分かりやすいです。
DLL から動的にファイルパスを指定する
1. 実行 DLL のパスを取得する
-
実行しているDLLの絶対パスを取得: System.Reflection.Assembly クラス
エントリポイントの取得やアセンブリを読み込みなどを定義しているクラスです。-
GetExecutingAssembly メソッド
実行中のコードを格納しているアセンブリを取得 -
Location プロパティ
読み込みファイルの完全パスを取得
-
GetExecutingAssembly メソッド
-
ディレクトリに関する処理:System.IO.Directory クラス 、System.IO.DirectoryInfo クラス
ディレクトリの作成・削除・検索などを定義しているクラスであり、Directory クラスは静的メソッド、DirectoryInfo クラスはインスタンスメソッドを定義しています。-
Directory.GetParent メソッド
指定したパスの親ディレクトリを取得 -
DirectoryInfo.FullName プロパティ
ディレクトリまたはファイルの絶対パスを返す
-
Directory.GetParent メソッド
// 実行している DLL のパス:(1)
string dllPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
// (1) のディレクトリ:(2)
System.IO.DirectoryInfo directoryInfo = Directory.GetParent(dllPath);
string dllDirectory = directoryInfo.FullName;
// (1) ⇒ C:\Zenn\SamplePath\SamplePath\bin\x64\Debug\net6.0\SamplePath.dll
// (2) ⇒ C:\Zenn\SamplePath\SamplePath\bin\x64\Debug\net6.0
2. 実行 DLL ディレクトリから入力データのディレクトリを算出する
// (2) ⇒ C:\Zenn\SamplePath\SamplePath\bin\x64\Debug\net6.0
// C:\Zenn\SamplePath\UnitTest\UT_input
実行 DLL のディレクトリ(2)から上記で定義している入力データのディレクトリまでは 5 階層戻ってパスを指定する必要があります。1 と同様に DirectoryInfo クラスを用います。
GetDirectories メソッドで一致するディレクトリを指定する方法もありますが、今回は戻るディレクトリ数を明示的に表現する方法になります。
-
DirectoryInfo.Parent プロパティ
指定したパスの親ディレクトリを取得
// Parent プロパティで 5 階層戻る
string unitTestDir = directoryInfo.Parent.Parent.Parent.Parent.Parent.FullName;
// Path.Combine メソッドでパスを結合する
string inputPath = Path.Combine(unitTestDir, "UT_input", inputFileName);
まとめ
実行 DLL から他のディレクトリを絶対パスで取得するには
- System.Reflection.Assembly クラス
DLL の実行パスを取得 - System.IO.Directory 、DirectoryInfo クラス
指定するディレクトリと同階層までのパスを取得 - System.IO.Path クラス
Combine メソッドでパスを結合
Discussion