【问题标题】:OutOfMemoryException when loading large string from Xml file从 Xml 文件加载大字符串时出现 OutOfMemoryException
【发布时间】:2010-12-10 06:36:01
【问题描述】:

我试图简单地从 Xml 文件中加载一个非常大的字符串并将其保存到 IXmlSerializable#ReadXml 方法内的临时文件中,正在使用的代码如下。

问题是我在reader.ReadStartElement("data"); 行上收到了OutOfMemoryExceptionXmlReader 似乎正在尝试预加载值字符串,因为在这种情况下它约为 500Mb,因此无法为其分配 StringBuilder

有没有更好的方法将此字符串复制到文件中,或者有什么方法可以绕过XmlReader 的预加载?

public void ReadXml(XmlReader reader)
{
    // Read other elements

    reader.ReadStartElement("data");

    this.dataFile = Path.GetTempFileName();
    FileStream tempFile = File.Create(this.dataFile);

    char[] buffer = new char[CHUNK_SIZE];
    int count;

    using (StreamWriter writer = new StreamWriter(tempFile))
    {
        while ((count = reader.ReadValueChunk(buffer, 0, CHUNK_SIZE)) != 0)
        {
            writer.Write(buffer, 0, count);
        }
    }
    reader.ReadEndElement();
}

【问题讨论】:

  • 哎哟;那是……棘手。我认为现在建议 xml 可能不是 500Mb 机箱的正确格式为时已晚?
  • 我不会使用 xml 并且你是否曾经解析它给它一个文件流,所以它不会一次读取整个字符串。因为作为 unicode 字符串,您已经将大小加倍(如果它存储为 ascii)。
  • 通常它远不及 500Mb,这只是压力测试的一部分。它可以是 500Mb(甚至更大),所以它需要支持这一点。这不应该被存储为字符串,它最初是,但是一旦我意识到它可以有多大,我就改变了这种分块和流式读写。

标签: c# xml


【解决方案1】:

找到了解决办法,问题不在IXmlSerializable#ReadXml方法上,实际上是在调用XmlSerializer#Deserialize的方法上。原来我有这个:

private void OpenSavedData(StreamReader strmReader, string fileName)
{
    XmlSerializer serializer = new XmlSerializer(typeof(SavedData));
    SavedData savedData = serializer.Deserialize(strmReader) as SavedData;

    // Process data
}

默认情况下Deserialize 会生成一个XmlTextReader 以传递给ReadXml 方法。如果我真的通过了ReadStartElement 调用,我会发现XmlTextReader 不支持GetValueChunk

相反,我需要使用XmlReader.Create 方法自己实例化一个XmlReader。这将创建一个不预加载值并支持分块的实现。

private void OpenSavedData(StreamReader strmReader, string fileName)
{
    XmlSerializer serializer = new XmlSerializer(typeof(SavedData));

    XmlReaderSettings settings = new XmlReaderSettings();
    settings.CloseInput = true;
    settings.IgnoreWhitespace = true;

    SavedData savedData = null;

    using (XmlReader xmlReader = XmlReader.Create(strmReader, settings))
    {
        savedData = serializer.Deserialize(xmlReader) as SavedData;
    }

    // Process data
}

这将允许ReadXml 调用成功。

【讨论】:

    猜你喜欢
    • 2016-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-14
    • 1970-01-01
    • 1970-01-01
    • 2016-07-17
    • 1970-01-01
    相关资源
    最近更新 更多