* .wav形式のほぼ14,000,000のオーディオサンプルを含むディレクトリがあります。
すべてのプレーンストレージ、サブディレクトリなし。
ファイルをループしたいのですが、そのフォルダーでDirectoryInfo.GetFiles()
を使用すると、アプリケーション全体が数分間フリーズします!
これは別の方法でできますか?おそらく1000を読んで、それらを処理してから、次の1000などを取得しますか?
EnumerateFiles DirectoryInfoクラスのメソッドを試しましたか?
MSDNが言うように
EnumerateFiles
メソッドとGetFiles
メソッドは次のように異なります。EnumerateFiles
を使用すると、コレクション全体が返される前にFileInfo
オブジェクトのコレクションの列挙を開始できます。GetFiles
を使用する場合、FileInfo
オブジェクトの配列全体が返されるのを待ってから、配列にアクセスできます。したがって、多くのファイルとディレクトリを操作している場合、EnumerateFiles
の方が効率的です。
.NET 4.0では、Directory.EnumerateFiles(...)
はDirectory.GetFiles(...)
のIEnumerable<string>
ではなくstring[]
であるため、すべてをバッファリングするのではなく、エントリをストリーミングできます。つまり.
foreach(var file in Directory.EnumerateFiles(path)) {
// ...
}
windowsファイルシステム自体の制限に達しています。ディレクトリ内のファイルの数が大きくなると(14Mがそのしきい値をはるかに超える)、ディレクトリへのアクセスが非常に遅くなります。一度に1つのファイルを読んでも、1000を読んでも、それは単にディレクトリアクセスです。
これを解決する1つの方法は、サブディレクトリを作成し、ファイルをグループに分割することです。各ディレクトリに1000〜5000がある場合(推測はできますが、実際の数値を試すことができます)、ファイルを開いたり、作成したり、削除したりすると、適切なパフォーマンスが得られます。
これが、クラスごとにファイルを作成するDoxygenのようなアプリケーションを見ると、このスキームに従い、すべてをランダムな名前を使用する2レベルのサブディレクトリに入れる理由です。
Win32 Api FindFile 関数を使用して、アプリをブロックせずに実行します。
System.Threading.Task (TPL)でDirectory.GetFilesを呼び出して、UIがフリーズしないようにすることもできます。
楽しい。
public List<string> LoadPathToAllFiles(string pathToFolder, int numberOfFilesToReturn)
{
var dirInfo = new DirectoryInfo(pathToFolder);
var firstFiles = dirInfo.EnumerateFiles().Take(numberOfFilesToReturn).ToList();
return firstFiles.Select(l => l.FullName).ToList();
}
私は、単一のディレクトリにある大きなファイルに頻繁にアクセスするというこの問題に直面しました。サブディレクトリは良い選択肢ですが、すぐにでもそれらは時々あまり助けを提供しません。私が今やっていることは、インデックスファイルを作成することです。これは、ディレクトリ内のすべてのファイルの名前を持つテキストファイルです(そのディレクトリにファイルを作成している場合)。次に、インデックスファイルを読み取り、ディレクトリから実際のファイルを開いて処理します