Ошибка "Этот поток не поддерживает операции поиска" в С#
Я пытаюсь получить изображение с 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;
Что я делаю с неправильными парнями?
Ответы
Ответ 1
Вероятно, вы хотите что-то подобное. Либо проверка длины терпит неудачу, либо 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, поэтому это имеет смысл.
Ответ 2
Используйте StreamReader вместо:
HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(url);
WebResponse myResp = myReq.GetResponse();
StreamReader reader = new StreamReader(myResp.GetResponseStream());
return reader.ReadToEnd();
(Примечание - выше приведена String
вместо массива байтов)
Ответ 3
Вы не можете запросить HTTP-соединение по своей длине. Возможно, сервер заблаговременно отправит вам длину, но (а) этот заголовок часто отсутствует и (б) он не гарантированно будет правильным.
Вместо этого вы должны:
- Создайте фиксированную длину
byte[]
, которую вы передаете методу Stream.Read
- Создайте
List<byte>
- После каждого чтения вызовите
List.AddRange
, чтобы добавить содержимое буфера с фиксированной длиной в свой список байтов.
Обратите внимание, что последний вызов Read
будет возвращать меньше, чем полное количество байтов, которые вы просили. Убедитесь, что вы добавили только количество байтов на ваш List<byte>
, а не весь byte[]
, или вы получите мусор в конце списка.
Ответ 4
Если сервер не отправляет спецификацию длины в заголовке HTTP, размер потока неизвестен, поэтому вы получаете ошибку при попытке использовать свойство Length
.
Прочитайте поток в меньших кусках, пока не достигнете конца потока.
Ответ 5
Длина потока не может быть прочитана из потока, поскольку получатель не знает, сколько байтов отправит отправитель. Попробуйте поместить протокол поверх http и отправить, то есть длину как первый элемент в потоке.
Ответ 6
С изображениями вам не нужно читать количество байтов вообще. Просто сделайте следующее:
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
}
Ответ 7
Возможно, вам следует использовать 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
.