特定の拡張子を持つファイルをディレクトリとそのすべてのサブディレクトリで検索するプログラムを作成しています。これはローカル ドライブとネットワーク ドライブの両方で使用されるため、パフォーマンスが少し問題になります。
私が現在使用している再帰メソッドは次のとおりです。
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にはイテレータブロックバージョンが組み込まれていることにも注意してください(EnumerateFiles
、EnumerateFileSystemEntries
)の方が高速である可能性がある(ファイルシステムへの直接アクセスが多く、配列が少ない)