OITA: Oika's Information Technological Activities

@oika 情報技術的活動日誌。

Directory.EnumerateFilesしながらファイルを増やすとどうなるか

.NET Framework 4で、配列を返すDirectory.GetFilesメソッドの代わりになる、
IEnumerableを返すDirectory.EnumerateFilesというメソッドが追加された。

GetFilesでは、すべてのファイルの検索を終えてから配列を作る必要があったのに対し、
EnumerateFilesは、ディレクトリ内のファイルを列挙しながら順次返す遅延評価のメソッドになっている。

普通、Foreachでコレクションを列挙する操作の中でコレクションに変更を加えると
InvalidOperationExceptionになるけれど、
EnumerateFilesでファイルを列挙しつつファイルの数を増やしたりすると
ひょっとして無限にファイルを増やし続けたりしないかなと思って
ドキドキしながらやってみた。

            //ディレクトリ作成
            const string FileDir = @"D:\tmp\";
            if (!Directory.Exists(FileDir)) Directory.CreateDirectory(FileDir);

            //最初にファイル1つ作成
            File.WriteAllText(Path.Combine(FileDir, "a.txt"), "テキストの中身");

            foreach (var f in Directory.EnumerateFiles(FileDir)) {

                string newFilePath = Path.Combine(FileDir, DateTime.Now.ToString("HHmmssff") + ".txt");
                File.WriteAllText(newFilePath, "テキストの中身");

                Thread.Sleep(100);  //ファイル名が同じにならないようにスリープ
            }

↑ディレクトリ内の1ファイルにつき、新しいテキストファイルを1つ作る処理になってる。
ループ内で新しく作ったファイルがそのまま列挙の対象になるなら
いつまでもファイルを作り続けるのではないかという実験。

結果は、例外も投げず、無限にファイルが増えることもなかった。
最初に作るa.txtと、それに対してforeachの中で作るファイルが1つだけ作られて終わり。
最初に用意するファイルを2つ以上にしても同じで、同数のファイルが作られるだけだった。

ためしに、列挙中にファイルを削除してしまうこともやってみた。

            //ディレクトリ作成
            const string FileDir = @"D:\tmp\";
            if (!Directory.Exists(FileDir)) Directory.CreateDirectory(FileDir);

            //最初にファイル2つ作成
            string fileAPath = Path.Combine(FileDir, "a.txt");
            string fileBPath = Path.Combine(FileDir, "b.txt");
            File.WriteAllText(fileAPath, "テキストの中身");
            File.WriteAllText(fileBPath, "テキストの中身");

            foreach (var f in Directory.EnumerateFiles(FileDir)) {

                Console.WriteLine(f);

                File.Delete(fileAPath); //初回で2つとも消してしまう
                File.Delete(fileBPath);
            }

これも例外を投げず、結果は2ファイル分のパスがちゃんと出力された。うーむ。

遅延評価とはいっても、列挙開始時に対象のファイルリストをちゃんと覚えておくような作りなんだろうか。
ちょっと思っていたのと違う動きだったので、どっか理解が間違っているかも。