2010-12-09 6 views
0

Ich versuche, eine sehr große Zeichenfolge einfach aus einer Xml-Datei zu laden und speichern Sie sie in eine temporäre Datei in der IXmlSerializable#ReadXml-Methode, der Code wird unten verwendet.OutOfMemoryException beim Laden großer Zeichenfolge aus Xml-Datei

Das Problem ist, ich bekomme eine OutOfMemoryException auf der reader.ReadStartElement("data"); Linie. Es scheint, dass die XmlReader versucht, die Wertzeichenfolge zu laden, und da es ~ 500Mb ist, in diesem Fall ist es nicht möglich, eine StringBuilder dafür zu reservieren.

Gibt es eine bessere Möglichkeit, diese Zeichenfolge in eine Datei zu kopieren oder die Vorladung der XmlReader zu umgehen?

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(); 
} 
+2

Autsch; das ist ... knifflig. Ich nehme an, es ist viel zu spät zu sagen, dass xml nicht das richtige Format für ein 500Mb-Gehäuse ist? –

+0

Ich würde nicht Xml verwenden und waren jemals Sie analysieren es geben Sie einen Dateistream, so dass es nicht die gesamte Zeichenfolge auf einmal. Denn als Unicode-String verdoppeln Sie bereits die Größe (wenn sie als ASCII gespeichert wird). – Will

+0

Normalerweise ist es nicht annähernd 500MB, dies ist nur ein Teil des Stresstests. Es kann 500MB (oder noch größer) sein, also muss es dies unterstützen. Nirgends soll das als String gespeichert werden, es war ursprünglich, aber sobald ich realisierte, wie groß es werden konnte, wechselte ich zu diesem Chunking und Streaming für das Lesen und Schreiben. – Nemo157

Antwort

2

eine Lösung gefunden, ist das Problem nicht in der IXmlSerializable#ReadXml Methode, es ist eigentlich in der Methode, die XmlSerializer#Deserialize aufruft. Ursprünglich hatte ich diese:

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

    // Process data 
} 

standardmäßig Deserialize eine XmlTextReader erzeugt auf die ReadXml Methode zu übergeben. Wenn ich es tatsächlich über den ReadStartElement Anruf hinaus geschafft hätte, hätte ich gefunden, dass XmlTextReaderGetValueChunk nicht unterstützt.

Stattdessen muss ich eine XmlReader selbst instanziieren mit der XmlReader.Create Methode. Dadurch wird eine Implementierung erstellt, die die Werte nicht vorlädt und Chunking unterstützt.

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 
} 

Dies ermöglicht dann die ReadXml Aufruf erfolgreich.

Verwandte Themen