ディレクトリとサブディレクトリ内のすべてのファイルを検索するより速い方法はありますか? 質問する

ディレクトリとサブディレクトリ内のすべてのファイルを検索するより速い方法はありますか? 質問する

特定の拡張子を持つファイルをディレクトリとそのすべてのサブディレクトリで検索するプログラムを作成しています。これはローカル ドライブとネットワーク ドライブの両方で使用されるため、パフォーマンスが少し問題になります。

私が現在使用している再帰メソッドは次のとおりです。

private void GetFileList(string fileSearchPattern, string rootFolderPath, List<FileInfo> files)
{
    DirectoryInfo di = new DirectoryInfo(rootFolderPath);

    FileInfo[] fiArr = di.GetFiles(fileSearchPattern, SearchOption.TopDirectoryOnly);
    files.AddRange(fiArr);

    DirectoryInfo[] diArr = di.GetDirectories();

    foreach (DirectoryInfo info in diArr)
    {
        GetFileList(fileSearchPattern, info.FullName, files);
    }
}

SearchOption を AllDirectories に設定して再帰メソッドを使用しないこともできますが、将来的には、現在スキャンされているフォルダーをユーザーに通知するコードを挿入する必要があります。

FileInfo オブジェクトのリストを作成している間、私が本当に気にしているのはファイルへのパスだけです。既存のファイル リストを新しいファイル リストと比較して、どのファイルが追加または削除されたかを確認したいと思います。このファイル パスのリストを生成するより高速な方法はありますか? 共有ネットワーク ドライブ上のファイルのクエリに関するこのファイル検索を最適化するためにできることはありますか?


アップデート1

まずすべてのサブディレクトリを検索し、次に各ディレクトリを繰り返しスキャンしてファイルを探すという同じことを実行する非再帰的な方法を作成しようとしました。方法は次のとおりです。

public static List<FileInfo> GetFileList(string fileSearchPattern, string rootFolderPath)
{
    DirectoryInfo rootDir = new DirectoryInfo(rootFolderPath);

    List<DirectoryInfo> dirList = new List<DirectoryInfo>(rootDir.GetDirectories("*", SearchOption.AllDirectories));
    dirList.Add(rootDir);

    List<FileInfo> fileList = new List<FileInfo>();

    foreach (DirectoryInfo dir in dirList)
    {
        fileList.AddRange(dir.GetFiles(fileSearchPattern, SearchOption.TopDirectoryOnly));
    }

    return fileList;
}

アップデート2

さて、ローカル フォルダーとリモート フォルダーの両方に多数のファイル (約 1200 個) がある状態で、いくつかのテストを実行しました。テストを実行したメソッドは次のとおりです。結果は次のとおりです。

  • GetFileListA(): 上記の更新における非再帰的なソリューション。これは Jay のソリューションと同等だと思います。
  • GetFileListB(): 元の質問からの再帰的方法
  • GetFileListC(): 静的 Directory.GetDirectories() メソッドですべてのディレクトリを取得します。次に、静的 Directory.GetFiles() メソッドですべてのファイル パスを取得します。リストを作成して返します。
  • GetFileListD(): Marc Gravellのソリューションはキューを使用してIEnumberableを返します。結果のIEnumerableをリストに入力しました。
    • ディレクトリ情報.GetFiles: 追加のメソッドは作成されません。ルート フォルダー パスから DirectoryInfo をインスタンス化しました。SearchOption.AllDirectories を使用して GetFiles を呼び出しました。
  • ディレクトリ.GetFiles: 追加のメソッドは作成されません。SearchOption.AllDirectories を使用して、ディレクトリの静的 GetFiles メソッドを呼び出しました。
Method                       Local Folder       Remote Folder
GetFileListA()               00:00.0781235      05:22.9000502
GetFileListB()               00:00.0624988      03:43.5425829
GetFileListC()               00:00.0624988      05:19.7282361
GetFileListD()               00:00.0468741      03:38.1208120
DirectoryInfo.GetFiles       00:00.0468741      03:45.4644210
Directory.GetFiles           00:00.0312494      03:48.0737459

. . . どうやら、Marc のものが一番速いようです。

ベストアンサー1

再帰とオブジェクトを回避する次の反復子ブロック バージョンを試してくださいInfo

public static IEnumerable<string> GetFileList(string fileSearchPattern, string rootFolderPath)
{
    Queue<string> pending = new Queue<string>();
    pending.Enqueue(rootFolderPath);
    string[] tmp;
    while (pending.Count > 0)
    {
        rootFolderPath = pending.Dequeue();
        try
        {
            tmp = Directory.GetFiles(rootFolderPath, fileSearchPattern);
        }
        catch (UnauthorizedAccessException)
        {
            continue;
        }
        for (int i = 0; i < tmp.Length; i++)
        {
            yield return tmp[i];
        }
        tmp = Directory.GetDirectories(rootFolderPath);
        for (int i = 0; i < tmp.Length; i++)
        {
            pending.Enqueue(tmp[i]);
        }
    }
}

また、4.0にはイテレータブロックバージョンが組み込まれていることにも注意してください(EnumerateFilesEnumerateFileSystemEntries)の方が高速である可能性がある(ファイルシステムへの直接アクセスが多く、配列が少ない)

おすすめ記事