从MemoryStream获取子字符串,而不将整个流转换为字符串

时间:2017-01-03 02:16:39

标签: c# substring string-matching memorystream

我希望能够有效地从MemoryStream中获取子字符串(最初来自zip中的xml文件)。目前,我将整个MemoryStream读取为一个字符串,然后搜索我想要的xml节点的开始和结束标记。这工作正常,但文本文件可能非常大,所以我想避免将整个MemoryStream转换为字符串,而只是直接从流中提取所需的xml文本部分。

最好的方法是什么?

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 个答案:

答案 0 :(得分: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 :(得分: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();
            }
        }

这假设开始和结束标签本身就在一条线上。如果没有,您可以通过像最初那样获得开始和结束索引来清理生成的文本字符串。