6

以前、ファイルをできるだけ速く見つけるために、特定のパスにあるすべてのファイルとディレクトリを高速に取得するという質問をしました。正規表現に一致するファイル名を見つけるために、そのソリューションを使用しています。

一部の非常に大きくて遅いハードドライブでは、実行に約1分かかるため、進行状況バーを表示したいと思っていました。他のリンクに投稿したその解決策では、進行状況バーを表示するためにトラバースする必要のあるファイルがさらにいくつあるかを知ることができません。

私が考えていた解決策の 1 つは、トラバースする予定のディレクトリのサイズを取得しようとすることでした。たとえば、フォルダを右クリックするC:\Usersと、そのディレクトリのサイズを推定できます。サイズがわかれば、見つかったすべてのファイルのサイズを追加して進行状況を表示できます。つまり、進行状況 = (現在のファイル サイズの合計) / ディレクトリ サイズ

何らかの理由で、そのディレクトリのサイズを効率的に取得できませんでした。

スタック オーバーフローに関するいくつかの質問では、次のアプローチが使用されます。

ここに画像の説明を入力

ただし、例外が発生し、ファイルを列挙できないことに注意してください。私は自分の c ドライブでその方法を試すことに興味があります。

その写真では、進行状況を示すためにファイルの数を数えようとしていました。そのアプローチを使用してファイルの数を効率的に取得することはおそらくできないでしょうhow to get the number of files on a directory人々が尋ねたとき、また人々が尋ねたときに、スタックオーバーフローに関するいくつかの答えを試してみましたhow the get the size f a directory

4

2 に答える 2

6

これを解決すると、いくつかの可能性のうちの 1 つが残されます...

  1. 進行状況が表示されない
  2. 計算に初期費用を使用する (Windows など)
  3. コストを計算しながら操作を実行する

速度がそれほど重要で、大きなディレクトリ ツリーが予想される場合は、これらのオプションの最後に頼ります。リンクされた質問Get all files and directory in specific path fast に回答を追加しました。これは、現在使用しているファイルとサイズよりも高速にカウントする方法を示しています。これをオプション #3 のマルチスレッド コードに組み合わせるには、次の手順を実行します...

static void Main()
{
    const string directory = @"C:\Program Files";
    // Create an enumeration of the files we will want to process that simply accumulates these values...
    long total = 0;
    var fcounter = new CSharpTest.Net.IO.FindFile(directory, "*", true, true, true);
    fcounter.RaiseOnAccessDenied = false;
    fcounter.FileFound +=
        (o, e) =>
            {
                if (!e.IsDirectory)
                {
                    Interlocked.Increment(ref total);
                }
            };

    // Start a high-priority thread to perform the accumulation
    Thread t = new Thread(fcounter.Find)
        {
            IsBackground = true, 
            Priority = ThreadPriority.AboveNormal, 
            Name = "file enum"
        };
    t.Start();

    // Allow the accumulator thread to get a head-start on us
    do { Thread.Sleep(100); }
    while (total < 100 && t.IsAlive);

    // Now we can process the files normally and update a percentage
    long count = 0, percentage = 0;
    var task = new CSharpTest.Net.IO.FindFile(directory, "*", true, true, true);
    task.RaiseOnAccessDenied = false;
    task.FileFound +=
        (o, e) =>
            {
                if (!e.IsDirectory)
                {
                    ProcessFile(e.FullPath);
                    // Update the percentage complete...
                    long progress = ++count * 100 / Interlocked.Read(ref total);
                    if (progress > percentage && progress <= 100)
                    {
                        percentage = progress;
                        Console.WriteLine("{0}% complete.", percentage);
                    }
                }
            };

    task.Find();
}

FindFile クラスの実装はFindFile.csにあります。

ファイル処理タスク (上記の ProcessFile 関数) のコストに応じて、大量のファイルの進行状況が非常にきれいに表示されるはずです。ファイル処理が非常に高速な場合は、列挙の開始と処理の開始の間のラグを増やしたい場合があります。

イベント引数はFindFile.FileFoundEventArgs型であり、変更可能なクラスであるため、値が変更されるため、イベント引数への参照を保持しないようにしてください。

理想的には、エラー処理を追加し、おそらく両方の列挙を中止する機能を追加する必要があります。列挙を中止するには、イベント引数に「CancelEnumeration」を設定します。

于 2012-09-17T18:28:20.630 に答える
4

ファイルシステムがデータを保存する方法が原因で、あなたが求めていることは不可能かもしれません。

ファイルシステムの制限です

ファイルを 1 つずつ列挙しない限り、フォルダーの合計サイズやフォルダー内の合計ファイル数を知る方法はありません。これらの情報はどちらもファイル システムに保存されません。

これが、Windows が多数のファイルを含むフォルダーをコピーする前のようなメッセージを表示する理由"Calculating space"です...実際には、フォルダー内にあるファイルの数を数え、それらのサイズを合計して、実際のコピー操作中に進行状況バーを表示できるようにします。 . (また、情報を使用して、コピーされるすべてのデータを保持するのに十分なスペースがコピー先にあるかどうかを確認します)。

また、フォルダを右クリックしてプロパティに移動すると、すべてのファイルを数えてすべてのファイル サイズを合計するのに時間がかかることに注意してください。これは、同じ制限が原因です。

フォルダーの大きさ、またはフォルダー内にあるファイルの数を知るには、ファイルを 1 つずつ列挙する必要があります。

高速ファイル列挙

もちろん、すでにご存じのとおり、列挙自体を行う方法はたくさんありますが、瞬時にできるものはありません。ファイル システムのUSN ジャーナルを使用してスキャンを実行してみてください。CodePlex でこのプロジェクトを見てみましょう: VB.NET の MFT スキャナー (コードは実際には C# にあります... 作者がなぜ VB.NET だと言っているのかわかりません) ... 私の IDE にすべてのファイルが見つかりました15 秒以内に SATA (SSD ではない) ドライブに接続し、311000 個のファイルが見つかりました。

探しているパス内のファイルのみが返されるように、ファイルをパスでフィルター処理する必要があります。しかし、それは仕事の簡単な部分です!

これがあなたのプロジェクトに役立つことを願っています...頑張ってください!

于 2012-09-17T16:58:10.463 に答える