20

数千のフォルダーを含むベース ディレクトリがあります。これらのフォルダー内には、1 ~ 10 個のファイルを含む 1 ~ 20 個のサブフォルダーが存在する可能性があります。60 日以上経過したすべてのファイルを削除したいと考えています。以下のコードを使用して、削除する必要があるファイルのリストを取得していました。

DirectoryInfo dirInfo = new DirectoryInfo(myBaseDirectory);
FileInfo[] oldFiles = 
  dirInfo.GetFiles("*.*", SearchOption.AllDirectories)
    .Where(t=>t.CreationTime < DateTime.Now.AddDays(-60)).ToArray();

しかし、これを約30分間実行しましたが、まだ完了していません。とにかく、上記の行のパフォーマンスを潜在的に改善できることを誰かが見ることができるかどうか、またはパフォーマンスを向上させるためにこれに完全にアプローチする必要がある別の方法があるかどうかに興味がありますか? 提案?

4

7 に答える 7

27

これは(おそらく)得られるものと同じくらい良いです:

DateTime sixtyLess = DateTime.Now.AddDays(-60);
DirectoryInfo dirInfo = new DirectoryInfo(myBaseDirectory);
FileInfo[] oldFiles = 
    dirInfo.EnumerateFiles("*.*", SearchOption.AllDirectories)
           .AsParallel()
           .Where(fi => fi.CreationTime < sixtyLess).ToArray();

変更点:

  • 60 日間のDateTime一定性を減らし、CPU 負荷を減らしました。
  • 使用済みEnumerateFiles
  • クエリを並列化しました。

より短い時間で実行する必要があります (どれだけ短いかはわかりません)。

これは、データによって異なりますが、最初のソリューションよりも速くなったり遅くなったりする可能性のある別のソリューションです。

DateTime sixtyLess = DateTime.Now.AddDays(-60);
DirectoryInfo dirInfo = new DirectoryInfo(myBaseDirectory);
FileInfo[] oldFiles = 
     dirInfo.EnumerateDirectories()
            .AsParallel()
            .SelectMany(di => di.EnumerateFiles("*.*", SearchOption.AllDirectories)
                                .Where(fi => fi.CreationTime < sixtyLess))
            .ToArray();

ここでは、並列処理をメイン フォルダーの列挙に移動します。上記の変更のほとんどが適用されます。

于 2013-07-19T22:12:44.287 に答える
3

上記の回答 (#itsnotalie & #Chibueze Opata) のメソッド Get1 は、ルート ディレクトリ内のファイルをカウントするために欠落しているため、次のように読み取る必要があります。

private static int Get1(string myBaseDirectory)
{
    DirectoryInfo dirInfo = new DirectoryInfo(myBaseDirectory);
    return dirInfo.EnumerateDirectories()
               .AsParallel()
               .SelectMany(di => di.EnumerateFiles("*.*", SearchOption.AllDirectories))
               .Count() + dirInfo.EnumerateFiles("*.*", SearchOption.TopDirectoryOnly).Count();
}
于 2017-07-15T18:08:27.427 に答える
0

Linq を使用しています。特殊なケースでディレクトリを再帰的に検索するための独自のメソッドを作成すると、より高速になります。

public static DateTime retval = DateTime.Now.AddDays(-60);

public static void WalkDirectoryTree(System.IO.DirectoryInfo root)
{
    System.IO.FileInfo[] files = null;
    System.IO.DirectoryInfo[] subDirs = null;

    // First, process all the files directly under this folder 
    try
    {
        files = root.GetFiles("*.*");
    }
    // This is thrown if even one of the files requires permissions greater 
    // than the application provides. 
    catch (UnauthorizedAccessException e)
    {
        // This code just writes out the message and continues to recurse. 
        // You may decide to do something different here. For example, you 
        // can try to elevate your privileges and access the file again.
        log.Add(e.Message);
    }
    catch (System.IO.DirectoryNotFoundException e)
    {
        Console.WriteLine(e.Message);
    }

    if (files != null)
    {
        foreach (System.IO.FileInfo fi in files)
        {
          if (fi.LastWriteTime < retval)
          {
            oldFiles.Add(files[i]);
          }

            Console.WriteLine(fi.FullName);
        }

        // Now find all the subdirectories under this directory.
        subDirs = root.GetDirectories();

        foreach (System.IO.DirectoryInfo dirInfo in subDirs)
        {
            // Resursive call for each subdirectory.
            WalkDirectoryTree(dirInfo);
        }
    }            
}
于 2013-07-19T22:42:06.477 に答える
0

本当にパフォーマンスを向上させたい場合は、手を汚しNtQueryDirectoryFileて、大きなバッファ サイズで Windows の内部にある を使用してください。

FindFirstFileはすでに遅いですFindFirstFileExが、ネイティブ関数を直接呼び出すと最高のパフォーマンスが得られます。

于 2013-07-20T02:10:47.920 に答える