知っていたはずなのに、また引っかかってしまったから、戒めを込めてメモ。
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と同じ静的にしなければならない点にだけ注意。本来ならば、「変更される前のカレントディレクトリを保存しておく」方法よりは、こちらの方が応用性はありそうで、こちらを使うべきだろう。
例示されたコードでは確かめてませんが…
OpenFileDialog/SaveFileDialog の RestoreDirectory プロパティを true にしてから、ShowDialog() すれば、カレントディレクトリは移動しない筈です。