web-dev-qa-db-ja.com

大量のファイルを含むディレクトリからファイルを取得する

* .wav形式のほぼ14,000,000のオーディオサンプルを含むディレクトリがあります。

すべてのプレーンストレージ、サブディレクトリなし。

ファイルをループしたいのですが、そのフォルダーでDirectoryInfo.GetFiles()を使用すると、アプリケーション全体が数分間フリーズします!

これは別の方法でできますか?おそらく1000を読んで、それらを処理してから、次の1000などを取得しますか?

60
eddyuk

EnumerateFiles DirectoryInfoクラスのメソッドを試しましたか?

MSDNが言うように

EnumerateFilesメソッドとGetFilesメソッドは次のように異なります。EnumerateFilesを使用すると、コレクション全体が返される前にFileInfoオブジェクトのコレクションの列挙を開始できます。 GetFilesを使用する場合、FileInfoオブジェクトの配列全体が返されるのを待ってから、配列にアクセスできます。したがって、多くのファイルとディレクトリを操作している場合、EnumerateFilesの方が効率的です。

87
Haris Hasan

.NET 4.0では、Directory.EnumerateFiles(...)Directory.GetFiles(...)IEnumerable<string>ではなくstring[]であるため、すべてをバッファリングするのではなく、エントリをストリーミングできます。つまり.

foreach(var file in Directory.EnumerateFiles(path)) {
    // ...
}
44
Marc Gravell

windowsファイルシステム自体の制限に達しています。ディレクトリ内のファイルの数が大きくなると(14Mがそのしきい値をはるかに超える)、ディレクトリへのアクセスが非常に遅くなります。一度に1つのファイルを読んでも、1000を読んでも、それは単にディレクトリアクセスです。

これを解決する1つの方法は、サブディレクトリを作成し、ファイルをグループに分割することです。各ディレクトリに1000〜5000がある場合(推測はできますが、実際の数値を試すことができます)、ファイルを開いたり、作成したり、削除したりすると、適切なパフォーマンスが得られます。

これが、クラスごとにファイルを作成するDoxygenのようなアプリケーションを見ると、このスキームに従い、すべてをランダムな名前を使用する2レベルのサブディレクトリに入れる理由です。

17
DXM

Win32 Api FindFile 関数を使用して、アプリをブロックせずに実行します。

System.Threading.Task (TPL)でDirectory.GetFilesを呼び出して、UIがフリーズしないようにすることもできます。

6

楽しい。

    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();
    }
5
Jaryn

私は、単一のディレクトリにある大きなファイルに頻繁にアクセスするというこの問題に直面しました。サブディレクトリは良い選択肢ですが、すぐにでもそれらは時々あまり助けを提供しません。私が今やっていることは、インデックスファイルを作成することです。これは、ディレクトリ内のすべてのファイルの名前を持つテキストファイルです(そのディレクトリにファイルを作成している場合)。次に、インデックスファイルを読み取り、ディレクトリから実際のファイルを開いて処理します

3
Faizul Hussain