web-dev-qa-db-ja.com

エラー「このストリームはシーク操作をサポートしていません」C#

byteストリームを使用してURLから画像を取得しようとしています。しかし、私はこのエラーメッセージを受け取ります:

このストリームは、シーク操作をサポートしていません。

これは私のコードです:

byte[] b;
HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(url);
WebResponse myResp = myReq.GetResponse();

Stream stream = myResp.GetResponseStream();
int i;
using (BinaryReader br = new BinaryReader(stream))
{
    i = (int)(stream.Length);
    b = br.ReadBytes(i); // (500000);
}
myResp.Close();
return b;

私は間違った男を何をしていますか?

45
Yustme

おそらくこのようなものが必要です。長さのチェックに失敗するか、BinaryReaderが舞台裏でシークを実行しています。

HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(url);
WebResponse myResp = myReq.GetResponse();

byte[] b = null;
using( Stream stream = myResp.GetResponseStream() )
using( MemoryStream ms = new MemoryStream() )
{
  int count = 0;
  do
  {
    byte[] buf = new byte[1024];
    count = stream.Read(buf, 0, 1024);
    ms.Write(buf, 0, count);
  } while(stream.CanRead && count > 0);
  b = ms.ToArray();
}

編集:

リフレクターを使用して確認しましたが、失敗するのはstream.Lengthの呼び出しです。 GetResponseStreamはConnectStreamを返し、そのクラスのLengthプロパティは、見た例外をスローします。他の投稿者が述べたように、HTTP応答の長さを確実に取得することはできないため、これは理にかなっています。

70
ngoozeff

代わりに StreamReader を使用してください:

HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(url);
WebResponse myResp = myReq.GetResponse();

StreamReader reader = new StreamReader(myResp.GetResponseStream());
return reader.ReadToEnd();

(注-上記はバイト配列の代わりにStringを返します)

12
Justin

HTTP接続にその長さを確実に要求することはできません。サーバーに事前に長さを送信してもらうことは可能ですが、(a)そのヘッダーが欠落していることが多く、(b)正しいことが保証されていません。

代わりに:

  1. byte[]メソッドに渡す固定長Stream.Readを作成します
  2. List<byte>を作成します
  3. 読み取りごとに、List.AddRangeを呼び出して、固定長バッファーの内容をバイトリストに追加します

Readの最後の呼び出しは、要求したバイト数よりも少ない数を返すことに注意してください。 List<byte>全体ではなくbyte[]にそのバイト数だけを追加してください。そうしないと、リストの最後にゴミが入ります。

7
Tim Robinson

サーバーがHTTPヘッダーで長さの指定を送信しない場合、ストリームサイズは不明であるため、Lengthプロパティを使用しようとするとエラーが発生します。

ストリームの終わりに達するまで、ストリームを小さなチャンクで読み取ります。

5
Guffa

おそらく_System.Net.WebClient_ APIを使用する必要があります。既にclient.OpenRead(url)を使用している場合は、client.DownloadData(url)を使用します

_var client = new System.Net.WebClient();
byte[] buffer = client.DownloadData(url);
using (var stream = new MemoryStream(buffer))
{
    ... your code using the stream ...
}
_

明らかに、これはStreamが作成される前にすべてをダウンロードするため、Streamを使用する目的に反する可能性があります。 webClient.DownloadData("https://your.url")は、MemoryStreamに変換できるバイト配列を取得します。

1
James Esh

受信者は送信者が送信するバイト数を知らないため、ストリームの長さをストリームから読み取ることはできません。プロトコルをhttpの上に置き、ストリームの最初の項目として長さを送信してみてください。

0
schoetbi

画像では、バイト数を読み取る必要はまったくありません。これを行うだけです:

Image img = null;
string path = "http://www.example.com/image.jpg";
WebRequest request = WebRequest.Create(path);
req.Credentials = CredentialCache.DefaultCredentials; // in case your URL has Windows auth
WebResponse resp = req.GetResponse();

using( Stream stream = response.GetResponseStream() ) 
{
    img = Image.FromStream(stream);
    // then use the image
}
0
vapcguy