3

私の C# 3.0 アプリケーションは、フォルダーをトラバースし、フォルダー内で何らかの処理を行う必要があります。意味のある進行状況を示すには、フォルダーの総数を知る必要があります。

オプションで使用するDirectory.GetDirectoriesAllDirectories、約 100K のフォルダーがある 2Tb ハード ドライブで非常に長い時間がかかり、その操作でも進行状況を表示する必要があります。私ができる唯一の意味のあることは、再帰を使用Directory.GetDirectoriesして、すでに見つかった多数のディレクトリをユーザーに提示することです。ただし、これは最初のアプローチよりもさらに時間がかかります。

どちらのアプローチも遅すぎると思います。この番号をより速く取得する方法はありますか? たとえば、PInvoke?を使用していくつかのファイル テーブルから取得します。他のアイデアはありますか?

4

5 に答える 5

2

私の提案は、すべてのディレクトリを取得している間、アプリケーションが作業を行っている間に実際の進行状況をユーザーに表示する場合にのみ、無限にスクロールする進行状況バーをユーザーに表示することです。

このようにして、ユーザーは、すべてが発生している間、アプリケーションがバックグラウンドで動作していることを知ることができます.

于 2011-06-20T16:13:06.547 に答える
1

これを実装すると、最初のプレスキャンが最も遅くなることがわかりますが、フォルダー構造がキャッシュされるため、次の (フル) スキャンが高速化されます。

最初の N (2..4) レベルのフォルダーのみをカウントすることもできます。それはまだ遅いかもしれませんが、推定の進歩を可能にします. すべての下位レベルに同じ数のファイルが含まれていると仮定してください。


パート 2、P/Invoke の質問について

ここでの主なコストは真の低レベル I/O であり、(任意の) API のオーバーヘッドは無視できます。

おそらくGetFiles()EnumerateFiles()(Fx4) に置き換えることでメリットが得られます。プレスキャンよりもメインループの方がそうです。

于 2011-06-20T16:17:49.447 に答える
1

このようなことはなかなかできません。プログレス バーの大まかな見積もりを作成しようとしているだけなら、あまり粒度は必要ありませんよね? 第 1 レベルと第 2 レベルのサブディレクトリの数を把握するために、ディレクトリ ツリーを 1 レベルまたは 2 レベルだけ手動でトラバースすることをお勧めします。その後、これらのサブディレクトリのいずれかにヒットするたびに、進行状況バーを更新できます。これにより、計算にあまり時間をかけずに、意味のある進行状況バーが得られるはずです。

于 2011-06-20T16:18:26.677 に答える
0

私はファイルの非常に単純な列挙を書きました。進行は数学的に連続的です。つまり、後で何があっても低い値に変わることはありません。見積もりは、すべてのフォルダーが同じ数のファイルとサブフォルダーを保持するという考えに基づいています。これは明らかにほとんどの場合ではありませんが、合理的な考えを得るには十分です。

特に深い構造のキャッシングはほとんどないので、これは直接列挙するのとほぼ同じ速さで機能するはずです。

public static IEnumerable<Tuple<string, float>> EnumerateFiles (string root)
{
    var files = Directory.GetFiles (root);
    var dirs = Directory.GetDirectories (root);
    var fact = 1f / (float) (dirs.Length + 1); // this makes for a rough estimate

    for (int i = 0; i < files.Length; i++) {
        var file = files[i];
        var f = (float) i / (float) files.Length;
        f *= fact;
        yield return new Tuple<string, float> (file, f);
    }

    for (int i = 0; i < dirs.Length; i++) {
        var dir = dirs[i];
        foreach (var tuple in EnumerateFiles (dir)) {
            var f = tuple.Item2;
            f *= fact;
            f += (i + 1) * fact;
            yield return new Tuple<string, float> (tuple.Item1, f);
        }
    }
}
于 2012-10-12T12:54:15.150 に答える
0

FindFirstFileおよびFindNextFile APIについて調べます。あなたの場合、彼らはより速く働くと思います

于 2011-06-20T16:13:46.663 に答える