C#で再帰を使わずにフォルダ内のファイルを列挙する

再帰処理を使わないでC#でフォルダ階層をたどってファイルをリストアップする方法の紹介です。

最後に記載がありますが実際はフォルダを巡回する必要ありません。C#はAPIをひとつつ呼ぶだけで実装できます。

再帰処理を使ってファイルを列挙する

まずは古典的な再帰処理を使ったファイルの探索方法です。

// Program.cs

public static void Main(string[] args)
{
  string root = @"c:\sample";
  Foo(root);
}

public static void Foo(string parent)
{
    foreach (string dir in Directory.GetDirectories(parent))
    {
        Console.WriteLine($"dir={dir}");
        foreach (string file in Directory.GetFiles(dir))
        {
            Console.WriteLine($"  file={Path.GetFileName(file)}");
        }
        Foo(dir);
    }
}

再帰処理を使わずにファイルを列挙する

次に再帰処理を使わないファイルの探索方法です。標準APIで実現できます。

すごく昔からあるAPIなので実はフォルダの巡回が必要な時に再帰処理が必要なケースは稀によくあるのですが通常使わないと思います。

// Program.cs

public static void Main(string[] args)
{
  string root = @"c:\sample";
  Foo(root);
}

foreach (var dir in Directory.GetDirectories(path, "*", SearchOption.AllDirectories))
{
    Console.WriteLine($"dir={dir}");
    foreach (string file in Directory.GetFiles(dir))
    {
        Console.WriteLine($"  file={Path.GetFileName(file)}");
    }
}

ちなみに再帰処理を使わない方がパフォーマンスが3倍くらい良いです。従って特殊な要件が無ければ再帰処理を使わない方がおすすめです。

そもそもAPIが用意されている

紹介しておいてあれですが、特定のファイルのリストアップがしたいだけの場合以下APIがあらかじめ用意されているので先述の巡回処理は必要ありません(しかもこのAPIはさらに高速に動作します)

// 特定のフォルダ以下の全部取得する
string[] fileList = Directory.GetFiles(path, "*.txt", SearchOption.AllDirectories);

// 逐次取得する
IEnumerable<string> fileList = Directory.EnumerateFiles(path, "*.txt", SearchOption.AllDirectories);

ファイル数が一万とか予想される場合は Enumerate の方を使った方がPCのリソースにやさしいです。