2012-11-24 179 views
2

我一直在使用这个方便的函数来“美化”一个xml文档,以便它使用缩进和换行符进行格式化。但是对于较大的文档(〜1MB),出于某种原因,我在doc.Save(writer)上收到OutOfMemoryException。我该如何解决这个问题?XmlDocument.Save OutOfMemory异常

public static string BeautifyXmlDocument(XmlDocument doc) 
{ 
    MemoryStream sb = new MemoryStream(); 
    XmlWriterSettings s = new XmlWriterSettings(); 
    s.Indent = true; 
    s.IndentChars = " "; 
    s.NewLineChars = "\r\n"; 
    s.NewLineHandling = NewLineHandling.Replace; 
    s.Encoding = new UTF8Encoding(false); 
    XmlWriter writer = XmlWriter.Create(sb, s); 
    doc.Save(writer); 
    writer.Close(); 
    return Encoding.UTF8.GetString(sb.ToArray()); 
} 

堆栈跟踪:

at System.IO.MemoryStream.set_Capacity(Int32 value) 
at System.IO.MemoryStream.EnsureCapacity(Int32 value) 
at System.IO.MemoryStream.Write(Byte[] buffer, Int32 offset, Int32 count) 
at System.Xml.XmlUtf8RawTextWriter.FlushBuffer() 
at System.Xml.XmlUtf8RawTextWriter.RawText(Char* pSrcBegin, Char* pSrcEnd) 
at System.Xml.XmlUtf8RawTextWriter.RawText(String s) 
at System.Xml.XmlUtf8RawTextWriter.WriteFullEndElement(String prefix, String localName, String ns) 
at System.Xml.XmlUtf8RawTextWriterIndent.WriteFullEndElement(String prefix, String localName, String ns) 
at System.Xml.XmlWellFormedWriter.WriteFullEndElement() 
at System.Xml.XmlElement.WriteTo(XmlWriter w) 
at System.Xml.XmlElement.WriteContentTo(XmlWriter w) 
at System.Xml.XmlElement.WriteTo(XmlWriter w) 
at System.Xml.XmlElement.WriteContentTo(XmlWriter w) 
at System.Xml.XmlElement.WriteTo(XmlWriter w) 
at System.Xml.XmlElement.WriteContentTo(XmlWriter w) 
at System.Xml.XmlElement.WriteTo(XmlWriter w) 
at System.Xml.XmlElement.WriteContentTo(XmlWriter w) 
at System.Xml.XmlElement.WriteTo(XmlWriter w) 
at System.Xml.XmlElement.WriteContentTo(XmlWriter w) 
at System.Xml.XmlElement.WriteTo(XmlWriter w) 
at System.Xml.XmlDocument.Save(XmlWriter w) 

回答

1

也许尝试关闭流才回到你的字符串,“使用”的声明可以帮助在这里。 这对于5MB xml文件似乎可以正常工作。

public static string BeautifyXmlDocument(XmlDocument doc) 
     { 
      using (MemoryStream sb = new MemoryStream()) 
      { 
       XmlWriterSettings s = new XmlWriterSettings(); 
       s.Indent = true; 
       s.IndentChars = " "; 
       s.NewLineChars = "\r\n"; 
       s.NewLineHandling = NewLineHandling.Replace; 
       s.Encoding = new UTF8Encoding(false); 
       using (XmlWriter writer = XmlWriter.Create(sb, s)) 
       { 
        doc.Save(writer); 
        return Encoding.UTF8.GetString(sb.ToArray()); 
       } 
      } 
     } 
1

只要你的实施需要得到文档的完整字符串,有人总是可以创建一个XmlDocument即会引起OutOfMemoryException。到真的解决这个问题,你需要移动到使用Stream对象(例如任何TextWriter),以便在任何给定的时间只有一小部分文件真的在记忆中。如果您提供更多有关如何使用美化字符串的详细信息,我或其他人可能会想出可能有所帮助的东西。

另一方面,如果你不能改变你的实现以避免在内存中包含整个字符串,你应该改变你的发布实现来使用StringWriter并将其传递给XmlWriter.Create。这至少摆脱了一些内存压力,因为你不会有MemoryStream在内存中的最后string在同一时间:

public static string BeautifyXmlDocument(XmlDocument doc) 
{ 
    using (StringWriter sw = new StringWriter()) 
    { 
     XmlWriterSettings s = new XmlWriterSettings(); 
     s.Indent = true; 
     s.IndentChars = " "; 
     s.NewLineChars = "\r\n"; 
     s.NewLineHandling = NewLineHandling.Replace; 
     s.Encoding = new UTF8Encoding(false); 
     using (XmlWriter writer = XmlWriter.Create(sw, s)) 
     { 
      doc.Save(writer); 
     } 
     return sw.ToString(); 
    } 
} 
+0

我想你的功能和上面的一个,但二者之间仍然给OutOfMemoryExceptions 。在你的函数中,sw.ToString()现在给出了内存错误。我没有提到的一件事是我的程序将大约1.5GB的数据加载到内存中。所以,我怀疑可能对事情有影响。 XML只是一个配置文件,我用其他参数保存数据的文件名位置。 –

+0

我可以将我的配置直接序列化为一个xml文件,但人们想要查看它并使用文本编辑器对其进行修改,因此我需要首先对其进行美化。 –

+0

除非Xml文档很大(我个人发现加载到'XmlDocument'的125 meg文件大约有2个地址空间的限制),我会考虑减少其他区域的内存使用量。这可能是秸秆破碎骆驼的背部。至于在GUI上显示它,呃,我在那里没有答案。我想知道自己做一个有效的记忆方法。 –