我的C#3.0应用程序应该遍历文件夹并在其中执行一些操作。为了显示有意义的进展,我需要知道总文件夹数量。
如果我使用带有Directory.GetDirectories
选项的AllDirectories
,这需要很长时间才能在我的2Tb硬盘上使用大约100K文件夹,我甚至应该为该操作提供进展!我能做的唯一有意义的事情是使用递归Directory.GetDirectories
并向用户提供许多已经找到的目录。但是,这比第一种方法需要更长的时间。
我相信,这两种方法都太慢了。有没有办法让这个数字更快?例如。使用PInvoke
从某些文件表中获取?还有其他想法吗?
答案 0 :(得分:2)
我的建议是在获取所有目录时向用户显示无限滚动的进度条,并且只有在应用程序完成工作时向用户显示实际进度时才会显示。
这样一来,当一切都发生时,用户就会知道应用程序正在后台运行。
答案 1 :(得分:1)
如果你实现这个,你会发现你的第一次预扫描是最慢的,但它会加速下一次(完整)扫描,因为文件夹结构正在缓存。
可能只计算前N(2..4)级别的文件夹。这可能仍然很慢,但它将允许估计的进展。假设所有较低级别包含相同数量的文件。
关于P / Invoke问题的第2部分
您的主要成本是真正的低级I / O,(任何)API的开销可以忽略不计。
您可能会因使用GetFiles()
(Fx4)替换EnumerateFiles()
而受益。主循环比预扫描更多。
答案 2 :(得分:1)
这种事情很难做到。如果您只是想对进度条进行粗略估计,那么您不需要太多粒度,对吧?我建议手动遍历目录树只有一个或两个级别,以确定有多少个第一级和第二级子目录。然后,只要您点击其中一个子目录,就可以更新进度条。这应该给你一个有意义的进度条,而不需要花太多时间来计算。
答案 3 :(得分:0)
浏览FindFirstFile和FindNextFile API。我认为他们会在你的情况下更快地工作
答案 4 :(得分: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);
}
}
}