快速检索没有完整路径的子文件夹名称的方法

时间:2012-11-13 15:57:43

标签: c#

我知道那里有重复项,但是我尝试了大约10种方法,需要6ms到29ms之间的时间,每个文件夹平均需要大约10ms才能从返回的路径中解析出文件的名称。 Directory.GetDirectories()

我找到的最快System.IO.Path.GetFileName(fullPath),但只有string.SubString(string.LastIndexOf(@"\")的短暂余量;

我正在编写更好的Windows资源管理器版本,但展开C:\并显示所有子文件夹大约需要半秒钟。半秒可能看起来不多,但是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 安装Node21后 将childNode添加到Controls后:21 在码头之后:22 开始迭代新目录后:22 设置目录名后:29 安装Node29之后 将childNode添加到Controls后:30 码头之后:30 开始迭代新目录后:30 设置目录名后:37 安装Node38后 将childNode添加到Controls后:38 码头之后:39 开始迭代新目录后:39

2 个答案:

答案 0 :(得分:2)

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

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

因为它在启动时启动,所以它能够预先获得所有这些信息,这使得所有信息都可以立即运行。

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

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

答案 1 :(得分:2)

你访问时间很奇怪,我怀疑你真正的瓶颈在那里。例如,我刚刚运行了一个测试应用程序并得到了这个(注意:我有一个SSD,所以我的测试几乎消除了磁盘访问速度的影响):

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

那是微秒。大部分时间都花在将文件提取到数组中,之后解析文件名是微不足道的。

最重要的是:我建议您下载一个分析器(如EQUATEC),并检查您的时间花在哪里。

如果你想自己尝试一下,这是我的代码:

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);
    }
}