为了支持使用进度报告上传大型(实际上非常大,高达几千兆字节)的文件,我们开始使用带有PushStreamContent的HttpClient,如here所述。它工作简单,我们在两个流之间复制字节,这是一个代码示例:
private void PushContent(Stream src, Stream dest, int length)
{
const int bufferLength = 1024*1024*10;
var buffer = new byte[bufferLength];
var pos = 0;
while (pos < length)
{
var bytes = Math.Min(bufferLength, length - pos);
src.Read(buffer, 0, bytes);
dest.Write(buffer, 0, bytes);
pos += bufferLength;
dest.Flush();
Console.WriteLine($"Transferred {pos} bytes");
}
dest.Close();
}
但是在开始时,这个代码在传输320 MB之后引发了OutOfMemory异常,即使进程的内存消耗不是很高(大约500 MB)。修复此问题的原因是设置TransferEncodingChunked标志:
request.Headers.TransferEncodingChunked = true;
不仅我们能够在设置了这个标志的情况下传输大文件,内存消耗也减少了90%。
我没有找到任何需要使用TransferEncodingChunked的文档,它更像是一个试验和失败的过程,但在这种情况下似乎至关重要。我仍然感到疑惑为什么会抛出异常 - 内存消耗不是很高,是什么原因导致的?
答案 0 :(得分:4)
Chunked transfer encoding是1.1版中的数据传输机制 超文本传输协议(HTTP)中的数据发送方式 系列&#34; chunks&#34;。它使用Transfer-Encoding HTTP标头 Content-Length标头,它的早期版本 否则协议将需要。1因为Content-Length标头 没有使用,发件人不需要知道的长度 在开始向接收者发送响应之前的内容。 发件人之前可以开始传输动态生成的内容 知道该内容的总大小。
每个块的大小都是在块本身之前发送的 接收器可以告诉它何时完成接收数据 块。数据传输由最后一块长度终止 零。
如果我们从逻辑上思考,文件是在小块上发送的,这意味着当你完成一个块时,你就可以将它从内存中释放出来。最后,您可以减少内存消耗,因为您正在处理多个小块。