作業ディレクトリと実行ディレクトリという罠 - 相対パスに気をつけろ！

# まえがき

実行ファイル(`.exe`)と同じフォルダや相対パス上に設定ファイルなどを置くことがあると思います。
この際に、<b>作業ディレクトリ</b>（カレントディレクトリ）と<b>実行ディレクトリ</b>の違いを理解していないと、`.exe`ファイルをどこから呼び出すかによって、上記の設定ファイルなどのパスが見つからずファイルが開けないという事態を招きます。

※`.dll`の場合どうなるかについては本記事では扱っていませんので、参考サイト等をご確認ください。

# 先に結論

「まえがき」に書いたシーンでは、「[実験用ソースコード](https://qiita.com/kob58im/items/daf3757a38e9657aa950#%E5%AE%9F%E9%A8%93%E7%94%A8%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89)」の`ExecutionPathTest`メソッド内を参考に設定ファイルを開くようにすれば、基本的にはOKのはず。
（※ドライブ直下とかファイルサーバ上とかは未テストなので確証はない。。。）


# 実験結果ログ（コマンドプロンプト）

「[実験用ソースコード](https://qiita.com/kob58im/items/daf3757a38e9657aa950#%E5%AE%9F%E9%A8%93%E7%94%A8%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89)」を使って、実験してみました。

（`setting.txt`が実行ファイルと同じ階層のフォルダ直下に置いてあるケース。）


```text:実行ファイルのディレクトリで実行した場合

C:\SvnLocal\trunk\DirTest>CurDirExeDirTest.exe
--- relative path ---
[1]setting.txt
[1-check]Found.
[2]C:\SvnLocal\trunk\DirTest\setting.txt
[2-check]Found.

--- curent directory ---
[3]C:\SvnLocal\trunk\DirTest
[3-check]Found.

--- executing directory or file ---
[4]C:\SvnLocal\trunk\DirTest\CurDirExeDirTest.exe
[5]C:\SvnLocal\trunk\DirTest
[6]C:\SvnLocal\trunk\DirTest\setting.txt
[6-check]Found.
```

```text:実行ファイルとは異なるディレクトリで実行した場合

C:\SvnLocal\trunk\DirTest>cd ..

C:\SvnLocal\trunk>DirTest\CurDirExeDirTest.exe
--- relative path ---
[1]setting.txt
[1-check]Cannot found.
[2]C:\SvnLocal\trunk\setting.txt
[2-check]Cannot found.

--- curent directory ---
[3]C:\SvnLocal\trunk
[3-check]Cannot found.

--- executing directory or file ---
[4]C:\SvnLocal\trunk\DirTest\CurDirExeDirTest.exe
[5]C:\SvnLocal\trunk\DirTest
[6]C:\SvnLocal\trunk\DirTest\setting.txt
[6-check]Found.
```

結果：`[6]`のやりかたのみファイルを見つけられます。

# 実験用ソースコード

```csharp:CurDirExeDirTest.cs

using System;
using System.IO;

class CurDirExeDirTest
{
    static readonly string SettingFileName = "setting.txt";

    [STAThread]
    static void Main(string[] args)
    {
        RelativePathTest();
        CurrentPathTest();
        ExecutionPathTest();
    }
    
    static void RelativePathTest()
    {
        Console.WriteLine("--- relative path ---");
        
        Console.Write("[1]");
        Console.WriteLine(SettingFileName);

        if ( File.Exists(SettingFileName) ) {
            Console.WriteLine("[1-check]Found.");
        }
        else {
            Console.WriteLine("[1-check]Cannot found.");
        }

        string settingFilePathByRelPath = Path.GetFullPath(SettingFileName);
        Console.Write("[2]");
        Console.WriteLine(settingFilePathByRelPath);

        if ( File.Exists(settingFilePathByRelPath) ) {
            Console.WriteLine("[2-check]Found.");
        }
        else {
            Console.WriteLine("[2-check]Cannot found.");
        }
        
        Console.WriteLine("");
    }
    
    static void CurrentPathTest()
    {
        Console.WriteLine("--- curent directory ---");

        string curDir = Environment.CurrentDirectory; // Directory.GetCurrentDirectory() でも同様
        Console.Write("[3]");
        Console.WriteLine(curDir);

        string settingFilePathByCurDir = Path.Combine(curDir, SettingFileName);
        if ( File.Exists(settingFilePathByCurDir) ) {
            Console.WriteLine("[3-check]Found.");
        }
        else {
            Console.WriteLine("[3-check]Cannot found.");
        }
        
        Console.WriteLine("");
    }

    static void ExecutionPathTest()
    {
        Console.WriteLine("--- executing directory or file ---");

        string assemblyFullPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
        Console.Write("[4]");
        Console.WriteLine(assemblyFullPath);

        string execDirName = Path.GetDirectoryName(assemblyFullPath);
        Console.Write("[5]");
        Console.WriteLine(execDirName);
        
        string settingFilePathByExeDir = Path.Combine(execDirName, SettingFileName);
        Console.Write("[6]");
        Console.WriteLine(settingFilePathByExeDir);

        if ( File.Exists(settingFilePathByExeDir) ) {
            Console.WriteLine("[6-check]Found.");
        }
        else {
            Console.WriteLine("[6-check]Cannot found.");
        }

        Console.WriteLine("");
    }
}
```

# 参考サイト

 - [カレントディレクトリ（現在の作業ディレクトリ）を取得、設定する - .NET Tips (VB.NET,C#...)](https://dobon.net/vb/dotnet/file/currentdirectory.html)
 - [自分のアプリケーションの実行ファイルのパスを取得する、VB6のApp.Pathと同じ事を行うには？ - .NET Tips (VB.NET,C#...)](https://dobon.net/vb/dotnet/vb6/apppath.html)