2017-01-03 9 views
3

Я хотел бы иметь возможность эффективно получать подстроку из MemoryStream (первоначально из XML-файла в zip-файле). В настоящее время я читаю весь MemoryStream для строки, а затем ищем начальные и конечные теги узла xml, которого я хочу. Это прекрасно работает, но текстовый файл может быть очень большим, поэтому я хотел бы избежать преобразования всего MemoryStream в строку и вместо этого просто извлечь желаемый раздел XML-текста непосредственно из потока.Получите подстроку из MemoryStream без преобразования всего потока в строку

Каков наилучший способ для этого?

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

Вы можете создать «XmlReader» из потока памяти, чтобы избежать загрузки всего файла в память. – juharr

+1

@juharr: Напишите это как ответ. Другой путь - это королевская боль и, вероятно, не работает правильно. – Joshua

+1

Что такое zip-библиотека? Ваш текущий метод извлекает весь файл в MemoryStream, поэтому это может привести к исключению из памяти больших файлов. В .NET 4.5 ['ZipArchiveEntry.Open'] (https://msdn.microsoft.com/en-us/library/system.io.compression.ziparchiveentry.open) можно использовать для [потока файла] (http: //www.dotnetcurry.com/csharp/974/zip-archives-csharp-dotnet) – Slai

ответ

2

Если файл действительный файл XML, то вы должны быть в состоянии использовать XmlReader, чтобы избежать загрузки всего файла в память

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 
      } 
     } 
    } 
} 

Вы, вероятно, хотите, чтобы поймать потенциальных исключений, если файл не действительный xml.

1

Если предположить, что, так как это XML будет иметь разрывы строк, вероятно, было бы лучше использовать StreamReader ReadLine и поиск тегов в каждой строке. (Также обратите внимание, положить StreamReader в использовании, а также.)

Что-то вроде

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

Это предполагает, что метки начала и конца находятся на линии сами по себе. Если нет, вы можете очистить полученную текстовую строку, получив индекс начала и конца снова, как вы это делали.