3

我的 C# 3.0 应用程序应该遍历文件夹并在其中做一些事情。为了显示有意义的进展,我需要知道文件夹总数。

如果我使用Directory.GetDirectorieswithAllDirectories选项,这在我的 2Tb 硬盘驱动器上需要很长时间,大约有 100K 文件夹,即使是该操作,我也应该提供一个进度!我能做的唯一有意义的事情是使用递归Directory.GetDirectories并向用户展示一些已经找到的目录。然而,这比第一种方法需要更长的时间。

我相信,这两种方法都太慢了。有什么办法可以更快地得到这个号码?例如,使用 ? 从一些文件表中获取PInvoke?还有其他想法吗?

4

5 回答 5

2

我的建议是在您获取所有目录时简单地向用户显示一个无限滚动的进度条,并且仅在您的应用程序执行工作时向用户显示实际进度。

这样,当一切发生时,用户就会知道应用程序正在后台运行。

于 2011-06-20T16:13:06.547 回答
1

如果您实施此操作,您会发现您的第一次预扫描是最慢的,但它会加快下一次(完整)扫描,因为文件夹结构正在被缓存。

仅计算前 N (2..4) 级中的文件夹可能是一种选择。这可能仍然很慢,但它将允许估计的进展。假设所有较低级别包含相同数量的文件。


第 2 部分,关于 P/Invoke 问题

您的主要成本是真正的低级 I/O,(任何)API 的开销可以忽略不计。

您可能会从替换GetFiles()EnumerateFiles()(Fx4) 中受益。与预扫描相比,主循环更是如此。

于 2011-06-20T16:17:49.447 回答
1

这种事情很难做到。如果您只是想对进度条进行粗略估计,那么您不需要太多的粒度,对吧?我建议手动遍历目录树只有一层或两层,以确定有多少第一级和第二级子目录。然后,您可以在点击其中一个子目录时更新进度条。这应该会给你一个有意义的进度条,而不需要花费太多时间来计算。

于 2011-06-20T16:18:26.677 回答
0

探索FindFirstFileFindNextFile API。我认为他们会在你的情况下工作得更快

于 2011-06-20T16:13:46.663 回答
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);
        }
    }
}
于 2012-10-12T12:54:15.150 回答