web-dev-qa-db-ja.com

C#でHttp応答ストリームを2回読み取るにはどうすればよいですか?

次を介してHttp応答ストリームを2回読み取ろうとしています:

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のストリームを解析し、生データ(文字列形式)にアクセスしたいと思います。

何か案は?

37
greg7gkb

まず、それを新しい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;
}
70
Iain

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のコメント を見ましたが、それは適切な現在の回答であるため、独自の回答エントリを持つ必要があります。)

0
Jack Miller