🚎

[C#・Path]実行 DLL から動的にファイルパスを指定

2022/08/21に公開

開発言語として C# を使用して10ヶ月になります。🔟🌻

現在、組み込み系アプリケーションのソリューション開発に携わっています。 Visual Studio を用いて複数のプログラムを作成し、メインプログラム( exe ファイル)から多数の DLL を呼び出して処理を実行します。それぞれの DLL を作成すると単体テストを行い、動作保証を確認します。

今回のアプリケーションでは入力データを受け取るため、テストを実行する際はデータのファイルパスを指定する必要があります。データをフルパスで指定してもよいですが、 PATH クラス を使用することで効率的に指定することができ、汎用的なソースコードになります。🌭
https://docs.microsoft.com/ja-jp/dotnet/api/system.io.path?view=net-6.0
今回は実行 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 以上は配列で渡します)
https://docs.microsoft.com/ja-jp/dotnet/api/system.io.path.combine?view=net-6.0
今回はフォルダを下記のように定義します。

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 ドライブを指定する場合などは明示的にを記述する必要があります。

詳しくは下記が分かりやすいです。
https://dobon.net/vb/dotnet/file/pathcombine.html

DLL から動的にファイルパスを指定する

1. 実行 DLL のパスを取得する

  • 実行しているDLLの絶対パスを取得System.Reflection.Assembly クラス
    エントリポイントの取得やアセンブリを読み込みなどを定義しているクラスです。

    • GetExecutingAssembly メソッド
      実行中のコードを格納しているアセンブリを取得
    • Location プロパティ
      読み込みファイルの完全パスを取得
  • ディレクトリに関する処理System.IO.Directory クラスSystem.IO.DirectoryInfo クラス
    ディレクトリの作成・削除・検索などを定義しているクラスであり、Directory クラスは静的メソッド、DirectoryInfo クラスはインスタンスメソッドを定義しています。

// 実行している 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 メソッドで一致するディレクトリを指定する方法もありますが、今回は戻るディレクトリ数を明示的に表現する方法になります。

// Parent プロパティで 5 階層戻る
string unitTestDir = directoryInfo.Parent.Parent.Parent.Parent.Parent.FullName;
// Path.Combine メソッドでパスを結合する
string inputPath = Path.Combine(unitTestDir, "UT_input", inputFileName);

まとめ

実行 DLL から他のディレクトリを絶対パスで取得するには

  1. System.Reflection.Assembly クラス
    DLL の実行パスを取得
  2. System.IO.Directory 、DirectoryInfo クラス
    指定するディレクトリと同階層までのパスを取得
  3. System.IO.Path クラス
    Combine メソッドでパスを結合

Discussion