0

我知道那里有重复,但我尝试了大约 10 种方法,它需要 6 毫秒到 29 毫秒之间,每个文件夹平均大约需要 10 毫秒才能从Directory.GetDirectories().

我发现的最快的是System.IO.Path.GetFileName(fullPath),但仅差一点string.SubString(string.LastIndexOf(@"\")

C:\我正在编写一个更好的 Windows Explorer 版本,但展开并显示所有子文件夹大约需要半秒钟。半秒可能看起来不多,但是 Windows 和我看过的另一个程序会立即出现。

我唯一能想到的就是对文件进行索引并将索引存储为 XML,我想这可以在启动时完成。

我只是好奇 Windows 和另一个控件如何在同一台 PC 上更快地完成它。C# 和托管代码是否比非托管 C++ 慢?

更新:

这是日志条目的示例,我意识到使用 File.AppendAllText 必须打开和关闭文件,但是许多操作只需要 1 毫秒即可完成,因此唯一慢的时间是 SetDirectoryName,它的完成方式如下:

public void LoadChildNodes()
        {
            // clear the child nodes
            this.ChildPanel.Controls.Clear();

            // if this path exists
            if (Directory.Exists(this.Path))
            {
                // get the log
                WriteLogEntry("After Path Exists: " + stopWatch.Elapsed.Milliseconds.ToString());

                // get the directories for this node
                string[] tempDirectories = Directory.GetDirectories(this.Path);

                // get the log
                WriteLogEntry("After GetDirectories: " + stopWatch.Elapsed.Milliseconds.ToString());

                // if there rae one or more directories
                if ((tempDirectories != null) && (tempDirectories.Length > 0))
                {  
                    // reverse the list
                    List<string> directories = new List<string>();

                    // iterate the strings
                    foreach (string tempDirectory in tempDirectories)
                    {
                        // add this item
                        directories.Add(tempDirectory);
                    }

                    // now set the directories
                    directories.Reverse();

                    // log the time
                    WriteLogEntry("After Reverse Directories: " + stopWatch.Elapsed.Milliseconds.ToString());

                    // iterate the directory names
                    foreach (string directory in directories)
                    {
                        // log the time
                        WriteLogEntry("After Start Iterate New Directory: " + stopWatch.Elapsed.Milliseconds.ToString());

                        // create the childNode
                        ExplorerTreeNode childNode = new ExplorerTreeNode();

                        // the path for folders is the same as the name
                        string directoryName = System.IO.Path.GetFileName(directory);

                        // log the time
                        WriteLogEntry("After set directory name: " + stopWatch.Elapsed.Milliseconds.ToString());

                        // setup the node
                        childNode.SetupNode(directoryName, NodeTypeEnum.Folder, this.IconManager, this.Font, path);

                        // log the time
                        WriteLogEntry("After Setup Node" + stopWatch.Elapsed.Milliseconds.ToString());

                        // add this node
                        this.ChildPanel.Controls.Add(childNode);

                        // log the time
                        WriteLogEntry("After Add childNode to Controls: " + stopWatch.Elapsed.Milliseconds.ToString());

                        // dock to top
                        childNode.Dock = DockStyle.Top;

                        // log the time
                        WriteLogEntry("After Dock: " + stopWatch.Elapsed.Milliseconds.ToString());
                    }

                    // finished loading child nodes
                    stopWatch.Stop();
                    WriteLogEntry("Finished loading child nodes: " + stopWatch.Elapsed.Milliseconds.ToString());
                }                 
            }
        }

我试图避免购买控件,以便我可以使项目开源,但我想我只会购买它并且只提供可执行文件。

路径存在后:1 GetDirectories 后:2 反向目录后:3 开始迭代新目录后:3 设置目录名称后:20 设置节点后 21 将子节点添加到控件后:21 停靠后:22 开始迭代新目录后:22 设置后目录名称:29 设置节点后 29 将子节点添加到控件后:30 停靠后:30 开始迭代新目录后:30 设置目录名称后:37 设置节点后 38 将子节点添加到控件后:38 停靠后:39 开始迭代新目录后: 39

4

2 回答 2

2

You access times are strange, I doubt that your real bottleneck is there. For example, I just ran a test app and got this (note: I have an SSD, so my test pretty much removes the influence of disk access speed):

Finding all files inside E:\ (recursive)...
Directory.GetFiles found 91731 files in 10,600 ms: 115.6 microseconds/file
Path.GetFileName parsed 91731 files in 134 ms: 1.5 microseconds/file

That's microseconds. And most of the time is spent fetching the files into the array, parsing the file name is trivial after that.

The bottom line is: I would recommend that you download a profiler (like EQUATEC), and check where your time is being spent.

Here's my code if you'd like to try it yourself:

class Program
{
    static void Main(string[] args)
    {
        var stopwatch = new Stopwatch();
        var path = @"E:\";

        Console.WriteLine("Finding all files inside {0} (recursive)", path);

        stopwatch.Restart();
        var allFiles = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
        stopwatch.Stop();
        Output("Directory.GetFiles found", allFiles.Length, stopwatch.ElapsedMilliseconds);

        stopwatch.Restart();
        var filenames = allFiles.Select(Path.GetFileName).ToArray();
        stopwatch.Stop();
        Output("Path.GetFileName parsed", filenames.Length, stopwatch.ElapsedMilliseconds);

        Console.Read();
    }

    private static void Output(string action, int len, long timeMs)
    {
        Console.WriteLine("{0} {1} files in {2:#,##0} ms: {3:0.0} microseconds/file", action, len, timeMs, timeMs * 1000.0 / len);
    }
}
于 2012-11-13T16:26:51.943 回答
2

首先,Windows Explorer 实现了对 FAT 表的直接访问。这提供了相当大的速度。

其次,它结合使用缓存和挂钩到更改通知。这允许它知道其他应用程序/窗口何时创建文件和目录。

因为它在启动时启动,所以它能够预先获取所有这些信息,这使得一切看起来都在瞬间运行。

您会注意到访问网络驱动器时速度变慢。这是因为它一次只检索一个级别,同时缓存结果并在其他访问时刷新。

最后,我认为您还有其他事情要做。10ms 解析单个文件名有点极端。

于 2012-11-13T16:12:37.243 回答