【问题标题】:How can I speed up getting a directory's content in C#?如何加快在 C# 中获取目录的内容?
【发布时间】:2021-11-30 06:53:25
【问题描述】:

作为一个学习项目,我一直在从事“文件资源管理器”项目一段时间,并在尝试新的编码方式时获得一些乐趣。到目前为止一切进展顺利,我对自己设法弄清楚的事情感到非常满意。我遇到的障碍是速度。在 Windows 资源管理器中,如果您进入一个新目录(当然取决于版本和其他变量),只需几分钟即可列出所有文件和子目录。另一方面,我的应用程序仍然相当快,但会显着减慢目录中的项目。

我有这个函数,我在“导航”函数中调用它。我相信这是我可能会找到罪魁祸首和解决方案的地方:

    private void GetDirectoryContent(string directory)
    {
        txtPath.Text = directory;

        currentDirectoryFiles.Clear();
        filesList.Items.Clear();

        int longestName = 0;
        int longestType = 0;
        foreach (string item in Directory.GetDirectories(directory))
        {
            int nameLength = item.Substring(item.LastIndexOf('\\') + 1).Length;
            
            if (nameLength > longestName) longestName = nameLength;
            if ("Folder".Length > longestType) longestType = "Folder".Length;
        }

        foreach (string item in Directory.GetFiles(directory))
        {
            int nameLength = item.Substring(item.LastIndexOf('\\') + 1).Length;
            
            if (nameLength > longestName) longestName = nameLength;
            if (GetFileType(item).Length > longestType) longestType = GetFileType(item).Length;
        }

        filesList.Sorting = SortOrder.Ascending;
        filesList.View = View.Details;
        filesList.Columns.Clear();
        filesList.Columns.Add("Name", longestName * 8);
        filesList.Columns.Add("Date Modified", 160);
        filesList.Columns.Add("Type", longestType * 8);

        foreach (string item in Directory.GetDirectories(directory))
        {
            string name = item.Substring(item.LastIndexOf('\\') + 1);
            
            smallImageList.Images.Add(new Bitmap(Environment.CurrentDirectory + "\\Xplorer.ico"));
            ListViewItem row = new ListViewItem(name, smallImageList.Images.Count - 1); // Name
            row.SubItems.Add(Directory.GetLastWriteTime(item).ToString(CultureInfo.CurrentCulture)); // Date Modified
            row.SubItems.Add("Folder"); // Type
            row.Tag = "Folder";
            currentDirectoryFiles.Add(item);
            filesList.Items.Add(row);
        }

        foreach (string item in Directory.GetFiles(directory))
        {
            string name = item.Substring(item.LastIndexOf('\\') + 1);
            
            smallImageList.Images.Add(Icon.ExtractAssociatedIcon(item) ?? throw new InvalidOperationException());
            ListViewItem row = new ListViewItem(name, smallImageList.Images.Count - 1); // Name
            row.SubItems.Add(File.GetLastWriteTime(item).ToString(CultureInfo.CurrentCulture)); // Date Modified
            row.SubItems.Add(GetFileType(item)); // Type 
            row.Tag = "File";
            currentDirectoryFiles.Add(item);
            filesList.Items.Add(row);
        }
    }

我还是一个新手程序员,所以我知道很多代码可能会被压缩,但我实际上不知道如何,所以这就是我的主要问题。我怎样才能压缩/优化这个函数来加速结果(并且只是为了在以后的项目中遵循更好的实践。)

如果我遗漏了您可能需要的任何细节,请告诉我,因为我说我还是新手,不知道有什么可能会有所帮助。提前致谢!

【问题讨论】:

  • 首先,您将调用Directory.GetFilesDirectory.GetDirectories 两次。我建议您只调用一次,并将结果存储在您可以在 foreach 循环中使用的变量中。 (我还建议使用 Path.GetFilename 而不是使用手动字符串操作。)
  • 为什么要多次调用这些东西?同样值得注意的是,EnumerateFiles 不会等到它收集的每个文件系统条目才开始返回列表。配置文件以查看您的慢点实际在哪里;我可以想象图像处理位可能会产生一些影响
  • 非常感谢您的帮助!搞定了。
  • 请把解决方案放在下方答案区。
  • 在添加元素时暂停/恢复控件的布局也很有意义。例如,如果filesListSystem.Windows.Forms.ListBox,您可以通过filesList.BeginUpdate()filesList.EndUpdate() 来实现。

标签: c# performance file optimization explorer


【解决方案1】:

似乎是学习项目的不错选择:) 也许使用 DirectoryInfo 而不是使用字符串进行搜索。它会让你更容易,而且可能会更快一点

private void GetDirectoryContent(DirectoryInfo directory)
{
    //you could also leave it as string and write var dir = new DirectoryInfo(directory); 
    /*...*/
    foreach (DirectoryInfo item in directory.GetDirectories())
    {
        string name = item.Name; //.FullName would include the path   
        smallImageList.Images.Add(new Bitmap(Environment.CurrentDirectory + "\\Xplorer.ico"));
        ListViewItem row = new ListViewItem(name, smallImageList.Images.Count - 1); 
        row.SubItems.Add(item.LastWriteTime.ToString(CultureInfo.CurrentCulture))
        row.SubItems.Add("Folder"); // Type
        row.Tag = "Folder";
        currentDirectoryFiles.Add(item);
        filesList.Items.Add(row);
    }
 
    foreach (FileInfo item in directory.GetFiles())
    {
        /* also knows its name, extension, last write time, ...*/
    }
    /*...*/
}

如果你走得更远一点并且感觉舒服,也许还可以尝试一些新东西。我认为对你的学习项目有用的东西是 IEnumerables 或递归(它对于像文件系统这样的树状结构非常有用)

【讨论】:

    【解决方案2】:

    感谢大家的帮助!这是一个新功能,它的工作速度非常快!

    private void GetDirectoryContent(string directory)
    {
        txtPath.Text = directory;
    
        currentDirectoryFiles.Clear();
        filesList.Items.Clear();
    
        string[] files = Directory.EnumerateFiles(directory).ToArray();
        string[] directories = Directory.EnumerateDirectories(directory).ToArray();
    
        filesList.Sorting = SortOrder.Ascending;
        filesList.View = View.Details;
        filesList.Columns.Clear();
        filesList.Columns.Add("Name", 250);
        filesList.Columns.Add("Date Modified", 160);
        filesList.Columns.Add("Type", 125);
    
        foreach (string item in directories)
        {
            string name = item.Substring(item.LastIndexOf('\\') + 1);
            
            smallImageList.Images.Add(new Bitmap(Environment.CurrentDirectory + "\\Xplorer.ico"));
            ListViewItem row = new ListViewItem(name, smallImageList.Images.Count - 1); // Name
            row.SubItems.Add(Directory.GetLastWriteTime(item).ToString(CultureInfo.CurrentCulture)); // Date Modified
            row.SubItems.Add("Folder"); // Type
            row.Tag = "Folder";
            currentDirectoryFiles.Add(item);
            filesList.Items.Add(row);
        }
    
        foreach (string item in files)
        {
            string name = item.Substring(item.LastIndexOf('\\') + 1);
            
            smallImageList.Images.Add(Icon.ExtractAssociatedIcon(item) ?? throw new InvalidOperationException());
            ListViewItem row = new ListViewItem(name, smallImageList.Images.Count - 1); // Name
            row.SubItems.Add(File.GetLastWriteTime(item).ToString(CultureInfo.CurrentCulture)); // Date Modified
            row.SubItems.Add(GetFileType(item)); // Type 
            row.Tag = "File";
            currentDirectoryFiles.Add(item);
            filesList.Items.Add(row);
        }
    }
    

    【讨论】:

    • smallImageList.Images.Add(new Bitmap(Environment.CurrentDirectory + "\\Xplorer.ico")); 一遍又一遍地添加相同的图标。您只需要它的一份副本,然后将它的索引号重新用于需要相同图标的所有条目。所以在循环之前添加它,确定它的索引值,然后将相同的索引值传递给每个目录条目。
    猜你喜欢
    • 2011-04-08
    • 1970-01-01
    • 1970-01-01
    • 2010-09-06
    • 2023-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多