You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#通过HTTP传输10KB分块字节数组 解决低内存客户端下载内存异常

解决方案

现有代码的问题

  • 服务端文件读取逻辑不合理:File.ReadAllBytes会将整个70KB文件一次性加载到服务端内存,属于不必要的内存开销
  • HTTP头配置错误:ContentType参数错误填写为.bin,不符合HTTP规范,二进制文件的正确MIME类型为application/octet-stream
  • 输出缓冲未关闭:ASP.NET默认会开启响应输出缓冲,攒够缓冲区大小才会发送数据到客户端,即使代码里做了分块写入,实际客户端还是可能一次性收到全部内容
  • 分块传输逻辑缺失:没有明确声明分块传输,部分旧客户端会等待完整响应接收完成才返回给上层业务,还是会触发内存超限问题

修复后的服务端代码

public class FileDownloadHandler : IHttpHandler
{
    public bool IsReusable => true;

    public void ProcessRequest(HttpContext context)
    {
        var fileExtension = GettingExtension(context.Request.RawUrl);
        if (!fileExtension.Equals(".bin", StringComparison.InvariantCultureIgnoreCase))
        {
            context.Response.Write("Invalid extension");
            context.Response.Flush();
            return;
        }

        string fileName = @"C:\FileHandler\File\AA_GS_BUILD.bin";
        const int chunkSize = 10 * 1024; // 固定10KB分块大小

        context.Response.ClearContent();
        context.Response.ClearHeaders();
        context.Response.ContentType = "application/octet-stream";
        context.Response.AddHeader("Content-Disposition", "attachment; filename=AA_GS_BUILD.bin");
        // 关闭响应缓冲,写入数据立即发送到客户端
        context.Response.BufferOutput = false;

        // 用文件流逐块读取,服务端也不需要加载整个文件到内存
        using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
        {
            var buffer = new byte[chunkSize];
            int bytesRead;
            while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
            {
                // 只写入实际读取到的字节数,避免最后一块附带多余空字节
                context.Response.BinaryWrite(buffer.Take(bytesRead).ToArray());
                context.Response.Flush();
            }
        }
        context.Response.End();
    }

    public string GettingExtension(string rawUrl)
    {
        return rawUrl.Substring(rawUrl.LastIndexOf(".", StringComparison.Ordinal));
    }
}

客户端侧必须满足的实现要求

仅修改服务端无法完全解决问题,客户端必须配合实现流读取逻辑:

  • 禁止使用一次性读取完整响应的API,例如WebClient.DownloadData、HttpClient.GetByteArrayAsync等,这类API会将整个响应加载到内存中
  • 必须获取响应的原始流,每次从流中读取最多10KB的数据,读取到的内容直接写入本地文件,不要临时存放到内存的全局字节数组中
  • 参考C#客户端实现:
using (var client = new HttpClient())
using (var responseStream = await client.GetStreamAsync("你的下载接口地址"))
using (var fileStream = new FileStream("本地保存路径.bin", FileMode.Create, FileAccess.Write))
{
    var buffer = new byte[10 * 1024];
    int bytesRead;
    while ((bytesRead = await responseStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
    {
        await fileStream.WriteAsync(buffer, 0, bytesRead);
    }
}

内容的提问来源于stack exchange,提问作者shujaat siddiqui

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 22:36:02