搜索目录中的所有文件时显示进度

Ton*_*Nam 6 c# filesystems directoryinfo

我之前问过快速获取特定路径中的所有文件和目录的问题,以便尽可能地找到文件.我正在使用该解决方案,以便找到与正则表达式匹配的文件名.

我希望显示一个进度条,因为有一些非常大而慢的硬盘驱动器,它仍然需要大约1分钟才能执行.我在另一个链接上发布的解决方案无法让我知道为了让我显示进度条,还有多少文件丢失.

我正在考虑做的一个解决方案是尝试获取我正在计划遍历的目录的大小.例如,当我右键单击该文件夹时,C:\Users我可以估计该目录的大小.如果我能够知道大小,那么我将能够通过添加我找到的每个文件的大小来显示进度.换句话说,progress =(文件大小的当前总和)/目录大小

由于某种原因,我无法有效地获得该目录的大小.

有关堆栈溢出的一些问题使用以下方法:

在此输入图像描述

但请注意,我得到一个例外,无法枚举文件.我很高兴在我的驱动器上尝试这种方法.

在那张照片上,我试图计算文件数量以显示进度.我可能无法使用该方法有效地获取文件数量.当人们问起how to get the number of files on a directory并且人们问起时,我只是尝试堆栈溢出的一些答案how the get the size f a directory.

csh*_*net 6

解决这个问题会让你有几种可能性......

  1. 没有显示进度
  2. 使用前期成本进行计算(如Windows)
  3. 计算成本的同时执行操作

如果速度非常重要,并且您期望大型目录树,那么我将倾向于最后一个选项.我已经在链接问题上添加了答案快速获取特定路径中的所有文件和目录,这表明计算文件和大小的速度比您当前使用的更快.要将它组合成选项#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();
}
Run Code Online (Sandbox Code Playgroud)

的FindFile类的实现,可以发现FindFile.cs.

根据文件处理任务的成本(上面的ProcessFile函数),您应该看到大量文件的进度非常干净.如果文件处理速度非常快,则可能需要增加枚举开始和处理开始之间的延迟.

事件参数的类型为FindFile.FileFoundEventArgs,并且是一个可变类,因此请确保您不保留对事件参数的引用,因为它的值将更改.

理想情况下,您需要添加错误处理,并且可能需要中止两个枚举.可以通过在事件参数上设置"CancelEnumeration"来中止枚举.