2017-01-03 27 views
3

我希望能夠從MemoryStream(最初來自zip中的xml文件)中有效地獲取子字符串。目前,我將整個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(); 
      } 
     } 

這假定開始和結束標記都在自己的線路。如果沒有,你可以通過獲取起始和結束的索引來清理最終的文本字符串,就像你原來那樣。