var webRequest = HttpWebRequest.Create('url of a big file approx 700MB') as HttpWebRequest;
好的,我们准备好了。如果您 PUT 或 POST 您自己的流,情况会有所不同,但差异是类似的。
var webResponse = webRequest.GetResponse();
返回时GetResponse()
,它至少会读取所有 HTTP 标头。它很可能已经读取了重定向的标头,并对重定向到的 URI 进行了另一个请求。也有可能它实际上是在命中缓存(直接或因为 webserver setnt 304 Not Modified),但默认情况下,这些细节对你是隐藏的。
套接字缓冲区中可能会有更多字节。
using (BinaryReader ns = new BinaryReader(webResponse.GetResponseStream()))
{
至此,我们得到了一个代表网络流的流。
让我们删除Thread.Sleep()
它除了增加连接超时的风险之外什么都不做。即使假设它在等待时没有超时,连接也会“退出”发送字节,因为你没有读取它们,所以效果会比你通过故意放慢速度来减慢速度。
var buffer = ns.ReadBytes(bufferToRead);
此时,要么bufferToRead
已读取字节以创建 a ,要么byte[]
小于,bufferToRead
因为流的总大小小于该字节,在这种情况下buffer
包含整个流。这将需要尽可能长的时间。
}
此时,由于执行了成功的 HTTP GET,底层 Web 访问层可能会缓存响应(如果它非常大,则可能不会缓存 - 默认假设是非常大的请求不会重复很多,也不会受益来自缓存)。
如果发生错误条件,它们将引发异常,在这种情况下,将永远不会进行缓存(没有必要缓存错误的响应)。
无需睡觉,或以其他方式“等待”它。
值得考虑以下变体,它通过直接操作流而不是通过读取器在略低的级别上工作:
using(var stm = webResponse.GetResponseStream())
{
我们将直接处理流;
byte[] buffer = new byte[4096];
do
{
int read = stm.Read(buffer, 0, 4096);
这将返回最多4096 个字节。它可能会读得更少,因为它已经有一大块可用的字节并且它会立即返回那么多字节。如果它位于流的末尾,它只会返回 0 个字节,因此这为我们提供了等待和不等待之间的平衡——它承诺等待足够长的时间以获取至少一个字节,但不管它是否等到它得到所有 4096 字节都由流来选择是等待那么长还是返回更少字节更有效;
DoSomething(buffer, 0, read);
我们使用我们得到的字节。
} while(read != 0);
Read()
如果它位于流的末尾,则只给我们零字节。
}
同样,当流被释放时,响应可能会或可能不会被缓存。
如您所见,即使在最低级别的 .NET 中,我们也可以在使用 .NET 时访问HttpWebResponse
,无需添加代码来等待任何内容,因为我们总是这样做。
您可以使用对流的异步访问来避免等待,但是异步机制仍然意味着您可以在结果可用时获得结果。