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

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

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

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

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

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

在此处输入图像描述

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

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

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

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

如果速度非常重要,并且您期望大型目录树,那么我将倾向于最后一个选项。 我在链接问题上添加了答案快速获取特定路径中的所有文件和目录,这表明计算文件和大小的速度比您当前使用的更快。 要将它组合成选项#3的multithreading代码段,可以执行以下操作……

 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.cs中找到FindFile类实现。

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

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

理想情况下,您需要添加error handling,并且可能需要中止两个枚举。 可以通过在事件参数上设置“CancelEnumeration”来中止枚举。

由于文件系统如何存储数据,因此您可能无法提出要求。

这是文件系统限制

如果没有 逐个枚举文件,就无法知道文件夹总大小 ,也无法知道文件夹内的总文件数 。 这些信息都不存储在文件系统中。

这就是为什么Windows在复制具有大量文件的文件夹之前显示"Calculating space"类的消息…它实际上计算文件夹中有多少文件,并将它们的大小相加以便它可以在执行时显示进度条真正的复制操作。 (它还使用这些信息来了解目标是否有足够的空间来容纳所有被复制的数据)。

此外,当您右键单击文件夹并转到属性时,请注意,计算所有文件并汇总所有文件大小需要一些时间。 这是由同样的限制造成的。

要知道文件夹的大小,或文件夹中有多少文件,您必须逐个枚举文件。

快速文件枚举

当然,正如您已经知道的那样,有很多方法可以自己进行枚举…但没有一种方法可以瞬间完成。 您可以尝试使用USN Journal of the file system进行扫描。 看看CodePlex中的这个项目: VB.NET中的MFT Scanner ( 代码实际上是在C#中……不知道为什么作者说它是VB.NET )…它找到了我IDE中的所有文件SATA(不是SSD)驱动器在不到15秒的时间内就能找到311000个文件。

您必须按路径过滤文件,以便仅返回您正在查看的路径中的文件。 但这是工作中最容易的部分!

希望这对你的项目有所帮助……祝你好运!