如何在程序中快速加载XML

本文关键字:加载 XML 程序 | 更新日期: 2023-09-27 17:53:12

我正在创建一个小工具,该工具将包括XML树视图。处理小文件大小的XML文件没有问题,但是当我尝试加载一个大的XML文件(21MB大小)时,应用程序变得没有响应,加载XML需要花费太多时间,而且大多数时候根本不加载XML。是否有任何修复或调整,使以下代码更快?

public TreeView(string filename)
        {
            InitializeComponent();
            this.Text = filename;
            XmlDataDocument xmldoc = new XmlDataDocument();
            XmlNode xmlnode;
            FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
            xmldoc.Load(fs);
            xmlnode = xmldoc.ChildNodes[1];
            treeView1.Nodes.Clear();
            treeView1.Nodes.Add(new TreeNode(xmldoc.DocumentElement.Name));
            TreeNode tNode;
            tNode = treeView1.Nodes[0];
            AddNode(xmlnode, tNode);
        }
        private void AddNode(XmlNode inXmlNode, TreeNode inTreeNode)
        {
            XmlNode xNode;
            TreeNode tNode;
            XmlNodeList nodeList;
            int i = 0;
            if (inXmlNode.HasChildNodes)
            {
                nodeList = inXmlNode.ChildNodes;
                for (i = 0; i <= nodeList.Count - 1; i++)
                {
                    xNode = inXmlNode.ChildNodes[i];
                    inTreeNode.Nodes.Add(new TreeNode(xNode.Name));
                    tNode = inTreeNode.Nodes[i];
                    AddNode(xNode, tNode);
                }
            }
            else
            {
                inTreeNode.Text = inXmlNode.InnerText.ToString();
            }
        }

如何在程序中快速加载XML

您必须将加载部分与构建TreeView分开。

加载可以在后台线程(BackgroundWorker)上进行。

与TreeView相关的所有内容都必须发生在主线程上,但您可以通过使用SuspendLayout等来加快速度。

您可以尝试使用Parallel。ForEach用于子节点,以便跨核拆分内容。这将很难实现。

http://msdn.microsoft.com/en-us/library/dd991486.aspx

对于无响应的部分,您可以在BackgroundWorker中异步加载xml,也许构建树视图结构的整个过程可以这样完成,并在完成时加载到控件中。

这可能不会大大提高速度,但它将保持UI响应。记住,你不能直接从BackgroundWorker中运行的代码访问UI,你必须通过Dispatcher调用它,像这样:

this.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
{
     // Execute code that works with UI controls
}));

两个小建议:与其添加一个节点然后查找它,不如在一个临时变量中创建它,然后从那里使用它。您可以使用foreach环而不是for环。

代替

nodeList = inXmlNode.ChildNodes;
for (i = 0; i <= nodeList.Count - 1; i++)
{
    xNode = inXmlNode.ChildNodes[i];
    inTreeNode.Nodes.Add(new TreeNode(xNode.Name));
    tNode = inTreeNode.Nodes[i];
    AddNode(xNode, tNode);
}

foreach (var node in inXmlNode.ChildNodes)
{
    tNode = new TreeNode(node.Name);
    inTreeNode.Nodes.Add(tNode);
    AddNode(node, tNode);
}

不是使用XmlDataDocument,而是将代码更改为使用XmlReader,因为该类在处理XML文件时提供了最高的性能。XmlReader是一个抽象类,可以从文件或任何其他数据流中读取数据。当从文件中读取时,不需要一次加载整个文档。

更多信息在这里:shanselman的快速概述
性能:LINQ to XML vs XmlDocument vs XmlReader

首先,在处理大文件时应该真正切换到类似sax的方法。参考在c#代码中解析(大)XML的最佳方法是什么?对于一个可能的解。

现在你有了一个可靠的方法来读取文件,无论文件有多大,都不会导致系统崩溃。

下一步是填充你的treeview,正如你所说的,你需要在一个单独的线程中做这件事,我建议使用backgroundworker,因为它们非常容易使用。

当发生变化时更新UI,我不熟悉winforms,但如果它支持ObservableCollection,我建议使用thous.