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.
精彩评论