如何在 C# 中两次读取 Http 响应流?
Posted
技术标签:
【中文标题】如何在 C# 中两次读取 Http 响应流?【英文标题】:How can I read an Http response stream twice in C#? 【发布时间】:2010-09-13 23:01:47 【问题描述】:我正在尝试通过以下方式读取 Http 响应流两次:
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
stream = response.GetResponseStream();
RssReader reader = new RssReader(stream);
do
element = reader.Read();
if (element is RssChannel)
feed.Channels.Add((RssChannel)element);
while (element != null);
StreamReader sr = new StreamReader(stream);
feed._FeedRawData = sr.ReadToEnd();
但是,当 StreamReader 代码执行时,没有返回任何数据,因为流现已到达末尾。我试图通过 stream.Position = 0 重置流,但这会引发异常(我认为是因为流无法手动更改其位置)。
基本上,我想解析 XML 流并访问原始数据(字符串格式)。
有什么想法吗?
【问题讨论】:
【参考方案1】:按照Iain 的建议将流复制到MemoryStream 是正确的方法。但由于 .NET Framework 4(2010 年发布)我们有 Stream.CopyTo。文档中的示例:
// Create the streams.
MemoryStream destination = new MemoryStream();
using (FileStream source = File.Open(@"c:\temp\data.dat",
FileMode.Open))
Console.WriteLine("Source length: 0", source.Length.ToString());
// Copy source to destination.
source.CopyTo(destination);
Console.WriteLine("Destination length: 0", destination.Length.ToString());
之后,您可以随意阅读destination
:
// re-set to beginning and convert stream to string
destination.Position = 0;
StreamReader streamReader = new StreamReader(destination);
string text = streamReader.ReadToEnd();
// re-set to beginning and read again
destination.Position = 0;
RssReader cssReader = new RssReader(destination);
(我见过Endy's comment,但由于它是一个合适的当前答案,它应该有自己的答案条目。)
【讨论】:
【参考方案2】:首先将其复制到一个新的 MemoryStream 中。然后,您可以根据需要多次重新读取 MemoryStream:
Stream responseStream = CopyAndClose(resp.GetResponseStream());
// Do something with the stream
responseStream.Position = 0;
// Do something with the stream again
private static Stream CopyAndClose(Stream inputStream)
const int readSize = 256;
byte[] buffer = new byte[readSize];
MemoryStream ms = new MemoryStream();
int count = inputStream.Read(buffer, 0, readSize);
while (count > 0)
ms.Write(buffer, 0, count);
count = inputStream.Read(buffer, 0, readSize);
ms.Position = 0;
inputStream.Close();
return ms;
【讨论】:
这里有一个小建议 - 我经常看到对 Seek 的调用,其中 Position 属性会更简单且更具可读性,例如ms.位置 = 0;只是对未来代码的想法。 另一条评论——上述内容永远不会关闭传入的流。可能值得创建一个 确实 关闭流的“CopyAndClose”方法,这样您就可以保持简单的调用语法。 哇,接近我的英雄了.. 我目前正在读你的书,Skeet 先生 :-) 你关于关闭(并用方法名称告诉)的建议正是我的想法上面的代码。 .net 4 及更高版本有更短的复制流方式:CopyTo【参考方案3】:您是否尝试过重置流位置? 如果这不起作用,您可以将流复制到 MemoryStream 并在那里您可以根据需要随时重置位置(即重置为 0)。
【讨论】:
以上是关于如何在 C# 中两次读取 Http 响应流?的主要内容,如果未能解决你的问题,请参考以下文章