Ошибка "Этот поток не поддерживает операции поиска" в C#

Я пытаюсь получить изображение из URL с помощью byte поток. Но я получаю это сообщение об ошибке:

Этот поток не поддерживает операции поиска.

Это мой код:

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;

Что я делаю не так, ребята?

7 ответов

Решение

Вы, вероятно, хотите что-то подобное. Либо проверка длины не удалась, либо 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-ответа, так что это имеет смысл.

Вместо этого используйте StreamReader:

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

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

(Примечание - выше возвращается String вместо байтового массива)

Вы не можете достоверно запросить HTTP-соединение для его длины. Можно заставить сервер отправлять вам длину заранее, но (а) этот заголовок часто отсутствует и (б) он не гарантированно будет правильным.

Вместо этого вы должны:

  1. Создать фиксированную длину byte[] что вы передаете Stream.Read метод
  2. Создать List<byte>
  3. После каждого чтения звоните List.AddRange добавить содержимое буфера фиксированной длины в список байтов

Обратите внимание, что последний звонок Read вернет меньше, чем полное количество байтов, которые вы просили. Убедитесь, что вы добавляете только это количество байтов к вашему List<byte> а не весь byte[], или вы получите мусор в конце вашего списка.

Если сервер не отправляет спецификацию длины в заголовке HTTP, размер потока неизвестен, поэтому вы получаете сообщение об ошибке при попытке использовать Length имущество.

Читайте поток небольшими порциями, пока не достигнете конца потока.

С изображениями вам вообще не нужно читать количество байтов. Просто сделай это:

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
}

Возможно, вам следует использовать 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,

Длина потока не может быть прочитана из потока, так как получатель не знает, сколько байтов отправит отправитель. Попробуйте поместить протокол поверх http и отправить, то есть длину, в качестве первого элемента в потоке.

Другие вопросы по тегам