从 MemoryStream 获取子字符串而不将整个流转换为字符串
Posted
技术标签:
【中文标题】从 MemoryStream 获取子字符串而不将整个流转换为字符串【英文标题】:Get substring from MemoryStream without converting entire stream to string 【发布时间】: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
【参考方案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 的索引来清理生成的文本字符串。
【讨论】:
以上是关于从 MemoryStream 获取子字符串而不将整个流转换为字符串的主要内容,如果未能解决你的问题,请参考以下文章