2011-06-20 7 views
3

私のC#3.0アプリケーションは、フォルダ内を走査し、内部でいくつかの処理を行う必要があります。意味のある進歩を示すために、私は合計フォルダ数を知る必要があります。サブフォルダの数を素早く見積もる

AllDirectoriesオプションを使ってDirectory.GetDirectoriesオプションを使用すると、フォルダが約100Kの2TBハードドライブでは非常に時間がかかります。私ができる唯一の意味があるのは、再帰的なDirectory.GetDirectoriesを使用して、すでに見つかっているいくつかのディレクトリをユーザに提示することです。しかし、これは第1のアプローチよりもさらに時間がかかる。

私は両方のアプローチが遅すぎると信じています。この番号を早く取得する方法はありますか?例えば。 PInvokeを使用していくつかのファイルテーブルから取得しますか?他のアイデア?

答えて

1

このようなことは難しいです。プログレスバーのおおよその見積もりをしようとしているだけであれば、あまり細かくする必要はありません。私は手動でディレクトリツリーを1〜2レベルだけ深くトラバースして、そこに第1レベルと第2レベルのサブディレクトリがいくつあるか把握することをお勧めします。次に、それらのサブディレクトリの1つを押すたびにプログレスバーを更新できます。それは、計算に時間をかけすぎることなく、意味のある進歩バーを与えるべきです。

+0

ありがとうございます - これはまさに私の考えです。他の選択肢が見つからない場合は、この方法を選択します(いくつかの魔法の場所から素早く番号を引き出す魔法の方法)。 – Alex

+0

Alex:ファイルシステムはあなたが望む情報を保存しないので、それを見つける唯一の方法はスキャンすることです。 – Gabe

2

すべてのディレクトリを取得している間に、アプリケーションが作業を行っている間に実際の進捗状況を表示するときだけ、無限にスクロールするプログレスバーをユーザーに提示することをお勧めします。

このようにして、すべての状況が発生している間にアプリケーションがバックグラウンドで動作していることがわかります。

+0

あなたのご意見ありがとうございます、ジャスティン。これは問題を解決する簡単な方法です。しかし、わかっているように、マイクロソフトのガイドラインでは、無限のプログレスバーを避けることを推奨しています。どのくらいの仕事が遅れているかを知ることは常に良いことです。 – Alex

+0

@Alex - 作業量がわかっている場合に限り、有限の進捗状況を表示できます。あなたがわからないときは、むしろ間違ったものではなく、無限のプログレスバーを見ることになります。 –

+0

@Alex、たとえば、削除するファイルの数を計算する際に無限のプログレスバーが表示されることを考慮してください。ガイドラインは厳しくて速いルールではありません。私はあなたがこのようなWindows(Windowsの?Window?)の例に従うことを許されると思います。 –

0

FindFirstFileおよびFindNextFile APIを参照してください。あなたのケースではもっと速く動作すると思う。

+0

なぜでしょうか(それは速くなりますか?) –

+0

ええ、それでも、木全体を横断することなくディレクトリの数を知ることはできません。これは遅い部分です。 – Gabe

+0

良いアイデア - Win APIは.NETのアナログよりも速いことがあります。しかし、NTFS/FATテーブルにそのような番号がすでにあるのだろうかと思います。 – Alex

1

これを実装すると、最初の事前スキャンが最も遅いが、フォルダ構造がキャッシュされているため次の(完全な)スキャンが高速になることがわかる。

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


パート2、P /呼び出しの質問に関する

あなたの主なコストは、ここにある真の低水準I/Oは、(任意の)APIのオーバーヘッドが無視できる程度である、です。

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

+0

コメントをいただきありがとうございます - これは既にGabeが与えてくれたものと同じですが、私も考えました。 – Alex

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); 
     } 
    } 
} 
関連する問題