2017-01-03 3 views
3

Ich würde gerne in der Lage, eine Teilzeichenfolge aus einem MemoryStream (die stammt ursprünglich aus einer XML-Datei in einer Zip) effizient zu erhalten. Momentan lese ich den gesamten MemoryStream in einen String und suche dann nach den Start- und End-Tags des gewünschten XML-Knotens. Das funktioniert gut, aber die Textdatei kann sehr groß sein, deshalb möchte ich vermeiden, den gesamten MemoryStream in eine Zeichenkette umzuwandeln und stattdessen einfach den gewünschten Abschnitt des XML-Textes direkt aus dem Stream zu extrahieren.Get Teilstring von MemoryStream ohne Konvertierung gesamten Stream in String

Was ist der beste Weg, um darüber zu gehen?

string xmlText; 
using (var zip = ZipFile.Read(zipFileName)) 
{ 
    var ze = zip[zipPath]; 
    using (var ms = new MemoryStream()) 
    { 
     ze.Extract(ms); 
     ms.Position = 0; 
     using(var sr = new StreamReader(ms)) 
     { 
      xmlText = sr.ReadToEnd(); 
     } 
    } 
} 

string startTag = "<someTag>"; 
string endTag = "</someTag>"; 
int startIndex = xmlText.IndexOf(startTag, StringComparison.Ordinal); 
int endIndex = xmlText.IndexOf(endTag, startIndex, StringComparison.Ordinal) + endTag.Length - 1; 
xmlText = xmlText.Substring(startIndex, endIndex - startIndex + 1); 
+2

Sie könnten einen 'XmlReader' aus dem Speicherstream erstellen, um zu vermeiden, dass die gesamte Datei in den Speicher geladen wird. – juharr

+1

@juharr: Schreiben Sie das als Antwort auf. Der andere Weg wird ein königlicher Schmerz sein und wahrscheinlich nicht richtig funktionieren. – Joshua

+1

Welche Zip-Bibliothek ist das? Ihre aktuelle Methode extrahiert die gesamte Datei in MemoryStream, so dass es zu einer Nichtspeicherausnahme für große Dateien kommen kann. In .NET 4.5 kann ['ZipArchiveEntry.Open'] (https://msdn.microsoft.com/en-us/library/system.io.compression.ziparchiveentry.open) verwendet werden, um [die Datei zu streamen] (http: //www.dotnetcurry.com/csharp/974/zip-archives-csharp-dotnet) – Slai

Antwort

2

Wenn die Datei eine gültige XML-Datei ist, dann sollten Sie in der Lage sein, eine XmlReader zu verwenden, um zu vermeiden, die gesamte Datei in den Speicher geladen

string xmlText; 
using (var zip = ZipFile.Read(zipFileName)) 
{ 
    var ze = zip[zipPath]; 
    using (var ms = new MemoryStream()) 
    { 
     ze.Extract(ms); 
     ms.Position = 0; 
     using (var xml = XmlReader.Create(ms)) 
     { 
      if(xml.ReadToFollowing("someTag")) 
      { 
       xmlText = xml.ReadInnerXml(); 
      } 
      else 
      { 
       // <someTag> not found 
      } 
     } 
    } 
} 

Sie wahrscheinlich mögliche Ausnahmen fangen werden soll, wenn die Datei nicht ist gültiges XML

1

dass Unter der Annahme, da es xml ist es Zeilenumbrüche haben wird, wäre es wahrscheinlich am besten, Streamreadline zu verwenden und für Ihre Tags in jeder Zeile suchen. (Beachten Sie auch, setzen Sie Ihren Stream in einem und verwenden.)

So etwas wie

 using (var ms = new MemoryStream()) 
     { 
      ze.Extract(ms); 
      ms.Position = 0; 
      using (var sr = new StreamReader(ms)) 
      { 
       bool adding = false; 
       string startTag = "<someTag>"; 
       string endTag = "</someTag>"; 
       StringBuilder text = new StringBuilder(); 
       while (sr.Peek() >= 0) 
       { 
        string tmp = sr.ReadLine(); 
        if (!adding && tmp.Contains(startTag)) 
        { 
         adding = true; 
        } 
        if (adding) 
        { 
         text.Append(tmp); 
        } 
        if (tmp.Contains(endTag)) 
         break; 
       } 
       xmlText = text.ToString(); 
      } 
     } 

Dies setzt voraus, dass der Start- und End-Tags auf einer Linie von selbst. Wenn nicht, könnten Sie die resultierende Textzeichenfolge bereinigen, indem Sie den Index von Anfang und Ende wie ursprünglich erhalten.