2010-12-09 4 views
0

J'essaie simplement de charger une très grande chaîne à partir d'un fichier XML et de l'enregistrer dans un fichier temporaire à l'intérieur de la méthode IXmlSerializable#ReadXml, le code utilisé est ci-dessous. Le problème est que j'obtiens un OutOfMemoryException sur la ligne reader.ReadStartElement("data");. Il semble que le XmlReader tente de précharger la chaîne de valeur et comme il est ~ 500Mb dans ce cas, il n'attribue pas StringBuilder pour cela.OutOfMemoryException lors du chargement d'une grande chaîne à partir du fichier Xml

Existe-t-il une meilleure façon de copier cette chaîne dans un fichier ou de contourner le préchargement du 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(); 
} 
+2

Ouch; c'est ... difficile. Je suppose qu'il est trop tard pour suggérer que peut-être xml n'est pas le bon format pour une enceinte de 500Mb? –

+0

Je n'utiliserais pas xml et si vous l'avez toujours analysé, donnez-lui un flux de fichiers afin qu'il ne lise pas toute la chaîne à la fois. Parce que, en tant que chaîne unicode, vous doublez déjà la taille (si elle est stockée en tant que ASCII). – Will

+0

Normalement, il n'est nulle part près de 500 Mo, ce n'est qu'une partie des tests de stress. Il peut être 500Mb (ou même plus grand) mais il doit donc supporter cela. Nulle part est-ce censé être stocké sous forme de chaîne, il était à l'origine, mais une fois que j'ai réalisé à quel point il pouvait être gros, je suis passé à la lecture et à l'écriture. – Nemo157

Répondre

2

trouvé une solution, le problème est pas dans la méthode IXmlSerializable#ReadXml, il est en fait dans la méthode qui appelle XmlSerializer#Deserialize. Au départ, j'avais ceci:

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

    // Process data 
} 

Par défaut Deserialize génère un XmlTextReader pour passer à la méthode ReadXml. Si j'avais effectivement dépassé l'appel ReadStartElement, j'aurais trouvé que XmlTextReader ne prend pas en charge GetValueChunk.

Au lieu de cela, j'ai besoin d'instancier un XmlReader moi-même en utilisant la méthode XmlReader.Create. Cela créera une implémentation qui ne précharge pas les valeurs et prend en charge le découpage.

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 
} 

Ceci permet ensuite à l'appel ReadXml de réussir.

Questions connexes