开发者

OutOfMemoryException when loading large string from Xml file

I'm trying to simply load a very large string from an Xml file and save it to a temporary file inside the IXmlSerializable#ReadXml method, the code being used is below.

The problem is I'm getting an OutOfMemoryExce开发者_Go百科ption on the reader.ReadStartElement("data"); line. It appears that the XmlReader is attempting to preload the value string and as it is ~500Mb in this case it is failing to allocate a StringBuilder for it.

Is there some better way of copying this string into a file, or some way to bypass the preloading of the 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();
}


Found a solution, the problem isn't in the IXmlSerializable#ReadXml method, it's actually in the method that calls XmlSerializer#Deserialize. Originally I had this:

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

    // Process data
}

By default Deserialize generates a XmlTextReader to pass to the ReadXml method. If I had actually made it past the ReadStartElement call I would have found that XmlTextReader doesn't support GetValueChunk.

Instead I need to instantiate an XmlReader myself using the XmlReader.Create method. This will create an implementation that doesn't preload the values and supports chunking.

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
}

This then allows the ReadXml call to succeed.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜