3

我正在构建一个自定义文件对话框,我的问题是加载时间太长。

对话框以一个InitialDirectory属性开始,我正在寻找一种方法来首先加载目录树InitialDirectory,然后是后台线程中的其余目录。

例如,如果InitialDirectoryC:\Users\User12345\MyDocuments,那么它应该加载所有文件夹

C:\
C:\用户
C:\User12345
C:\Users\User12345\MyDocuments

然后启动一个后台线程来加载所有剩余的目录。

有没有一种快速简便的方法来使用递归首先加载InitialDirectory, 而不是其他所有内容,而不复制任何项目?

我正在努力寻找一种高性能的方法来做到这一点,因为使用类似代码检查文件夹的存在if (!Directory.Contains(f => f.FullName == folder.FullName))会大大减慢负载。

我当前加载完整目录的代码如下所示:

private void LoadDirectory()
{
    string root = @"C:\";
    var rootNode = new DirectoryModel() { Name = root, FullName = root };
    this.Directory.Add(rootNode);

    DirectoryInfo info = new DirectoryInfo(root);
    IEnumerable<DirectoryInfo> subDirectories = info.GetDirectories()
            .Where(d => ((d.Attributes & FileAttributes.Hidden) != FileAttributes.Hidden)
                && ((d.Attributes & FileAttributes.System) != FileAttributes.System));

    LoadDirectories(subDirectories, root);
}

private void LoadDirectories(IEnumerable<DirectoryInfo> subDirs, string parentName)
{
    IEnumerable<DirectoryInfo> subdirectories;
    foreach (DirectoryInfo folder in subDirs)
    {
        var node = new DirectoryModel() { Name = folder.Name, FullName = folder.FullName, ParentName = parentName };

        Directory.Add(node);

        try
        {
            subdirectories = folder.GetDirectories("*", SearchOption.TopDirectoryOnly)
                .Where(d => ((d.Attributes & FileAttributes.Hidden) != FileAttributes.Hidden)
                    && ((d.Attributes & FileAttributes.System) != FileAttributes.System));
        }
        catch (UnauthorizedAccessException e)
        {
            continue;
        }
        catch (System.IO.DirectoryNotFoundException e)
        {
            continue;
        }

        if (subdirectories.Count() != 0)
            LoadDirectories(subdirectories, folder.FullName);
    }
}

请注意,该Directory集合是一个平面集合 - 数据模型中没有层次结构。

4

2 回答 2

3

这取决于您如何向用户展示您的数据,imo。

如果您使用TreeView控件,则可以轻松避免在后台加载所有数据,而只加载树的(就像您已经按照我的理解所做的那样)。

这样,拥有一个加载指定目录的所有子目录名称和文件的程序,您只需要等到用户单击即可看到[+]感兴趣的目录内容。所以你运行你的过程并填充树。

这实际上是我所知道的处理这类东西的最高性能方式,实际上你会在几乎所有“类似探索者”的产品中找到这种模式。这里的性能不是通过完美的算法实现的,而是通过定义更方便的行为模型来实现的。

希望这可以帮助。

于 2013-08-07T17:51:37.610 回答
0

为了展示 Tigran 的解决方案,实现此目的的一种方法是使用以下内容:

  1. 订阅树的 BeforeExpand 事件。

    private void BeforeExpand(object sender, BeforeExpandEventArgs e)
    {
        TreeListNode current = e.Node;
    
        if (current.Nodes.Count > 0)
            return;
    
        if (current.Tag is DriveInfo)
        {
            exampleTree.BeginUpdate();
            DriveInfo driveInfo = current.Tag as DriveInfo;
            LoadDirectories(current, driveInfo.RootDirectory);
            exampleTree.EndUpdate(true);
        }
        else if (current.Tag is DirectoryInfo)
        {
            exampleTree.BeginUpdate();
            LoadDirectories(current, (DirectoryInfo)current.Tag);
            exampleTree.EndUpdate(true);
        }
    }
    

这是 LoadDirectories() 方法:

    private void LoadDirectories(TreeListNode parent, DirectoryInfo directoryInfo)
    {
        DirectoryInfo[] directories = directoryInfo.GetDirectories();
        foreach (DirectoryInfo directory in directories)
        {
            if ((directory.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden) continue;
            TreeListNode child = new TreeListNode() { Tag = directory, Text = directory.Name };
            parent.Nodes.Add(child);
        }

        FileInfo[] files = directoryInfo.GetFiles();
        foreach (FileInfo file in files)
        {
            TreeListNode child = new TreeListNode() { Tag = file, Text = file.Name };
            parent.Nodes.Add(child);
        }
    }

高温下,

-赛格-

于 2013-09-03T13:02:40.363 回答