读取XML文件(文件大小> 500 MB)

时间:2018-02-28 10:46:26

标签: c# .net xml

我试图解析大型XML文件(大小约为600MB)并使用

它需要更长的时间,最后,整个过程都会中止。这个过程以一个例外结束。

消息:"线程已中止"

方法:

private string ReadXml(XmlTextReader reader, string fileName)
{
    string finalXML = "";
    string s1 = "";
    try
    {
        while (reader.Read())
        {
            switch (reader.NodeType)
            {
                case XmlNodeType.Element: // The node is an element.
                    s1 += "<" + reader.Name + ">";
                    break;
                case XmlNodeType.Text: //Display the text in each element.
                    s1 += reader.Value;
                    break;
                case XmlNodeType.EndElement: //Display the end of the element.
                    s1 += "</" + reader.Name + ">";
                    break;
            }
            finalXML = s1;
        }
    }
    catch (Exception ex)
    {
       Logger.Logger.LogMessage(ex, "File Processing error: " + fileName);
    }
    reader.Close();
    reader.Dispose();

    return finalXML;
}

然后阅读和脱盐:

string finalXML = string.Empty;
XmlTextReader reader = new XmlTextReader(unzipfile);
finalXML = await ReadXml(reader, fileName);

var xmlremovenamespae = Helper.RemoveAllNamespaces(finalXML);
XmlParseObjectNew.BizData myxml = new XmlParseObjectNew.BizData();

using (StringReader sr = new StringReader(xmlremovenamespae))
 {
       XmlSerializer serializer = new XmlSerializer(typeof(XmlParseObjectNew.BizData));
       myxml = (XmlParseObjectNew.BizData)serializer.Deserialize(sr);
 }

还有更好的阅读方式吗?解析大型xml文件?需要一个建议。

2 个答案:

答案 0 :(得分:1)

正如Jon Skeet和DiskJunky所提到的,问题是您的数据集太大而无法加载到内存中,并且您的代码未针对此进行优化。因此,各种课程为什么会给你一个“内存不足”的例外情况。

首先,字符串连接。由于字符串的工作方式,使用带有多个字符串的简单连接(a + b)通常是个坏主意。我建议在线查看如何有效地处理字符串连接(例如,Jon Skeet&#39; s Concatenating Strings Efficiently)。

然而,这是代码的优化,主要问题是您尝试加载到内存中的XML文件的大小。要处理大型数据集,通常情况下,如果您可以“流式传输”数据集更好。数据,处理数据块而不是整个文件。

由于您没有展示XML的示例,我冒昧地做了一个简单的例子来说明我的意思。

考虑您拥有以下XML:

<root>
   <specialelement>
      <value1>somevalue</value1>
      <value2>somevalue</value2>
   </specialelement>
   <specialelement>
      <value1>someothervalue</value1>
      <value2>someothervalue</value2>
   </specialelement>
   ... 
</root>

在这个XML中,您希望将specialelement解析为一个对象,具有以下类定义:

[XmlRoot("specialelement")]
public class ExampleClass
{
    [XmlElement(ElementName = "value1")]
    public string Value1 { get; set; }    
    [XmlElement(ElementName = "value2")]
    public string Value2 { get; set; }
}

我假设我们可以单独处理每个SpecialElement,并为此定义处理程序,如下所示:

public void HandleElement(ExampleClass item)
{
    // Process stuff
}

现在我们可以使用XmlTextReader分别读取XML中的每个元素,当我们到达specialelement时,我们会跟踪XML元素中包含的数据。当我们到达specialelement的末尾时,我们将其反序列化为一个对象并将其发送给我们的处理程序进行处理。例如:

using (var reader = new XmlTextReader( /* your inputstream */ ))
{
    // Buffer for the element contents
    StringBuilder sb = new StringBuilder(1000);

    // Read till next node
    while (reader.Read())
    {
        switch (reader.NodeType)
        {
            case XmlNodeType.Element: 
                // Clear the stringbuilder when we start with our element 
                if (string.Equals(reader.Name, "specialelement"))
                {
                    sb.Clear();
                }

                // Append current element without namespace
                sb.Append("<").Append(reader.Name).Append(">");
                break;

            case XmlNodeType.Text: //Display the text in each element.
                sb.Append(reader.Value);
                break;

            case XmlNodeType.EndElement: 

                // Append the closure element
                sb.Append("</").Append(reader.Name).Append(">");

                // Check if we have finished reading our element
                if (string.Equals(reader.Name, "specialelement"))
                {
                    // The stringbuilder now contains the entire 'SpecialElement' part
                    using (TextReader textReader = new StringReader(sb.ToString()))
                    {
                        // Deserialize
                        var deserializedElement = (ExampleClass)serializer.Deserialize(textReader);
                        // Send to handler
                        HandleElement(deserializedElement);
                    }
                }

                break;
        }
    }
}

当我们开始处理来自流的数据时,我们不必将整个文件加载到内存中。保持程序的内存使用率低(防止内存不足)。

结帐this fiddle以查看其实际效果。

请注意,这是一个快速示例,您仍有很多地方可以进一步改进和优化此代码。

答案 1 :(得分:1)

我试试这个并且工作正常。

  

fileName =&#34;您的文件路径&#34 ;;

     

尝试此代码,在几秒钟内解析大于500MB的XML文件。

using (TextReader textReader = new StreamReader(fileName))
  {
    using (XmlTextReader reader = new XmlTextReader(textReader))
      {                                   
       reader.Namespaces = false;
 XmlSerializer serializer = new XmlSerializer(typeof("YourXmlClassType"));
          parseData = ("YourXmlClassType")serializer.Deserialize(reader);
      }
  }