OpenFileDialog/SaveFileDialogの罠、カレントディレクトリの変更

知っていたはずなのに、また引っかかってしまったから、戒めを込めてメモ。

C#.NETにおけるFileDialogがカレントディレクトリを変更するバグ(?)

C#.NETのSystem.Windows.Forms.OpenFileDialogかSaveFileDialogを使用して、その中でディレクトリの移動操作などをすると、プログラム自体のカレントディレクトリが移動することがある。私は明らかにバグではないかと思っているのだが、もしかしたら仕様なのかもしれない。どのような場面で、このような事態が発生するのか例を出してみる。

異常を発生させる最小のプログラム例

class Program
{
    const string filename = "test.txt";

    [System.STAThread]
    static void Main(string[] args)
    {
        System.Windows.Forms.OpenFileDialog ofd = new System.Windows.Forms.OpenFileDialog();
        ofd.ShowDialog();

        //ダイアログボックス内でディレクトリを変える

        System.IO.StreamReader sr = new System.IO.StreamReader(filename);
        System.Console.WriteLine(sr.ReadLine());
        System.Console.ReadLine();
    }
}

「開く」を押した場合のみ、カレントディレクトリは変更される。つまり、その場合だけ、StreamReader部分で例外(FileNotFoundException)が発生する。

解決法

変更される前のカレントディレクトリを保存しておく

class Program
{
    const string filename = "test.txt";

    [System.STAThread]
    static void Main(string[] args)
    {
        string current = System.IO.Directory.GetCurrentDirectory();

        System.Windows.Forms.SaveFileDialog ofd = new System.Windows.Forms.SaveFileDialog();
        ofd.ShowDialog();

        System.IO.Directory.SetCurrentDirectory(current);

        //ダイアログボックス内でディレクトリを変える

        System.IO.StreamReader sr = new System.IO.StreamReader(filename);
        System.Console.WriteLine(sr.ReadLine());
        System.Console.ReadLine();
    }
}

少し汚いが、こういう方法も有効だ。

プログラムの実行パスを取得する

class Program
{
    static string filename = System.IO.Path.Combine(System.Windows.Forms.Application.StartupPath, "test.txt");

    [System.STAThread]
    static void Main(string[] args)
    {
        System.Windows.Forms.SaveFileDialog ofd = new System.Windows.Forms.SaveFileDialog();
        ofd.ShowDialog();

        //ダイアログボックス内でディレクトリを変える

        System.IO.StreamReader sr = new System.IO.StreamReader(filename);
        System.Console.WriteLine(sr.ReadLine());
        System.Console.ReadLine();
    }
}

そもそも、実行ファイルのパスを取得してしまおうという技。constでなくなり、Mainと同じ静的にしなければならない点にだけ注意。本来ならば、「変更される前のカレントディレクトリを保存しておく」方法よりは、こちらの方が応用性はありそうで、こちらを使うべきだろう。

参考URL

OpenFileDialog/SaveFileDialogの罠、カレントディレクトリの変更」への1件のフィードバック

  1. acha-ya

    例示されたコードでは確かめてませんが…
    OpenFileDialog/SaveFileDialog の RestoreDirectory プロパティを true にしてから、ShowDialog() すれば、カレントディレクトリは移動しない筈です。

コメントを残す

メールアドレスが公開されることはありません。