我正在尝试从{em> GET 请求GetResponseStream
并将其转换为byte[]
。 Stream 是不可搜索的,因此我无法访问stream.Length
。 response.ContentLength
不可靠。
private byte[] streamToBytes(Stream stream, int bufferSize = 4096)
{
byte[] buffer = new byte[bufferSize];
int read = 0;
int pos = 0;
List<byte> bytes = new List<byte>();
while (true) { // `bufferSize > read` does **not** mean stream end
while (bufferSize == (read = stream.Read(buffer, pos, bufferSize))) {
pos += read;
bytes.AddRange(buffer);
}
if (read > 0) {
byte[] _buffer = new byte[read];
Array.Copy(buffer, _buffer, read);
bytes.AddRange(_buffer);
} else break;
}
return bytes.ToArray();
}
在ArgumentOutOfRangeException
循环的第二次迭代中,Read
会被while
抛出。 MSDN says
ArgumentOutOfRangeException
偏移或计数为负数。
我知道这不可能是因为偏移(pos
)是0 + read >= 0
而 count (bufferSize
)是4096
为什么我会向我抛出异常?
我正在努力使streamToBytes
尽可能通用,以便我可以在将来的 async 方法中使用它。
如果请求如何帮助,这里是相关位
HttpWebRequest request = (HttpWebRequest)WebRequest.Create((new Uri("http://google.com")).ToString());
request.Method = "GET";
request.KeepAlive = true;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream stream = response.GetResponseStream();
byte[] responseBytes = streamToBytes(stream);
答案 0 :(得分:3)
作为一个更简单的选择:
using(var memStream = new MemoryStream())
{
stream.CopyTo(memStream);
return memStream.ToArray();
}
您的代码有两个错误:
offset
Read
是缓冲区的偏移量,而不是流中的位置(正如@Ulugbek已经注意到的那样)。这意味着您不再需要pos
变量。bufferSize == read
。您需要检查> 0
。所以你的阅读循环变为:
while ((read = stream.Read(buffer, 0, bufferSize)) > 0)
{
bytes.AddRange(buffer.Take(read));
}
您现在可以删除最后一个块的特殊处理。将您的代码简化为:
private byte[] streamToBytes(Stream stream, int bufferSize = 4096)
{
byte[] buffer = new byte[bufferSize];
int read = 0;
List<byte> bytes = new List<byte>();
while ((read = stream.Read(buffer, 0, bufferSize)) > 0)
{
bytes.AddRange(buffer.Take(read));
}
return bytes.ToArray();
}
使用List<byte>
代替MemoryStream
也不是一个好主意。 AddRange
需要单独迭代字节,而不是使用低级复制操作。用内存流替换列表,代码变为:
private byte[] streamToBytes(Stream stream, int bufferSize = 4096)
{
byte[] buffer = new byte[bufferSize];
int read = 0;
using(var bytes = new MemoryStream())
{
while ((read = stream.Read(buffer, 0, bufferSize)) > 0)
{
bytes.Write(buffer, 0, read);
}
return bytes.ToArray();
}
}
你甚至可以将它分成两部分,一部分复制到内存流中,另一部分处理内存流的创建并将其转换为字节数组:
private static void CopyStream(Stream source, Stream destination, int bufferSize = 4096)
{
byte[] buffer = new byte[bufferSize];
int read = 0;
while ((read = source.Read(buffer, 0, bufferSize)) > 0)
{
destination.Write(buffer, 0, read);
}
}
private static byte[] StreamToBytes(Stream stream, int bufferSize = 4096)
{
using(var memStream = new MemoryStream())
{
CopyStream(stream, memStream);
return memStream.ToArray();
}
}
这可能与Stream.CopyTo
内部的内容非常相似。
答案 1 :(得分:1)
更改
stream.Read(buffer, pos, bufferSize)
到
stream.Read(buffer, 0, bufferSize)