【问题标题】:Get substring from MemoryStream without converting entire stream to string从 MemoryStream 获取子字符串而不将整个流转换为字符串
【发布时间】:2017-05-17 01:47:06
【问题描述】:

我希望能够有效地从 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);

【问题讨论】:

  • 您可以从内存流中创建一个XmlReader,以避免将整个文件加载到内存中。
  • @juharr:把它写下来作为答案。另一种方法将是一种皇家痛苦,并且可能无法正常工作。
  • 那是什么压缩库?您当前的方法将整个文件提取到 MemoryStream 中,因此可能会导致大文件出现内存不足异常。在 .NET 4.5 中ZipArchiveEntry.Open 可用于stream the file
  • 它是 DotNetZip。我需要使用 .NET 4.0。
  • 似乎您可以使用ZipEntry.OpenReader 而不是.Extract,然后在该流上使用XmlReader.Create 而不是MemoryStream

标签: c# substring string-matching memorystream


【解决方案1】:

如果您的文件是有效的 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,您可能希望捕获潜在的异常。

【讨论】:

    【解决方案2】:

    假设由于它是 xml 它将有换行符,最好使用 StreamReader ReadLine 并在每一行中搜索您的标签。 (另请注意将您的 StreamReader 也放入 using 中。)

    类似

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

    这假设开始和结束标签本身在一行上。如果没有,您可以像原来一样通过再次获取 start 和 end 的索引来清理生成的文本字符串。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-06
      • 1970-01-01
      • 1970-01-01
      • 2015-07-04
      • 1970-01-01
      • 2017-07-03
      • 2019-02-13
      相关资源
      最近更新 更多