zoukankan      html  css  js  c++  java
  • ASP.NET Core下载大文件的实现

    当我们的ASP.NET Core网站需要支持下载大文件时,如果不做控制可能会导致用户在访问下载页面时发生无响应,使得浏览器崩溃。可以参考如下代码来避免这个问题。
     
    关于此代码的几点说明:
    1. 将数据分成较小的部分,然后将其移动到响应输出流以供下载,从而获取这些数据。
    2. 根据下载的文件类型来指定 Response.ContentType 。(这个网址可以找到大部分文件类型的对照表:http://tool.oschina.net/commons
    3. 在每次调用Response.Body.Write后记得调用 Response.Body.Flush()
    4. 在循环下载的过程中使用 HttpContext.RequestAborted.IsCancellationRequested 这个判断可以帮助程序尽早发现连接是否正常。若不正常,可以及早放弃下载,以释放所占用的服务器资源。
     
    本例使用ASP.NET Core MVC中Controller的Action来演示大文件的下载代码,根据需要也可以改为其它方式(例如ASP.NET Core的中间件)来做下载。
    using Microsoft.AspNetCore.Mvc;
    using System.IO;
    using System.Web;
    
    namespace AspNetCoreDownload.Controllers
    {
        public class HomeController : Controller
        {
            public IActionResult Index()
            {
                return View();
            }
    
            /// <summary>
            /// DownloadBigFile用于下载大文件,循环读取大文件的内容到服务器内存,然后发送给客户端浏览器
            /// </summary>
            public IActionResult DownloadBigFile()
            {
                var filePath = @"D:Download测试文档.xlsx";//要下载的文件地址,这个文件会被分成片段,通过循环逐步读取到ASP.NET Core中,然后发送给客户端浏览器
                var fileName = Path.GetFileName(filePath);//测试文档.xlsx
    
                int bufferSize = 1024;//这就是ASP.NET Core循环读取下载文件的缓存大小,这里我们设置为了1024字节,也就是说ASP.NET Core每次会从下载文件中读取1024字节的内容到服务器内存中,然后发送到客户端浏览器,这样避免了一次将整个下载文件都加载到服务器内存中,导致服务器崩溃
    
                Response.ContentType = "application/vnd.ms-excel";//由于我们下载的是一个Excel文件,所以设置ContentType为application/vnd.ms-excel
    
                var contentDisposition = "attachment;" + "filename=" + HttpUtility.UrlEncode(fileName);//在Response的Header中设置下载文件的文件名,这样客户端浏览器才能正确显示下载的文件名,注意这里要用HttpUtility.UrlEncode编码文件名,否则有些浏览器可能会显示乱码文件名
                Response.Headers.Add("Content-Disposition", new string[] { contentDisposition });
    
                //使用FileStream开始循环读取要下载文件的内容
                using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                {
                    using (Response.Body)//调用Response.Body.Dispose()并不会关闭客户端浏览器到ASP.NET Core服务器的连接,之后还可以继续往Response.Body中写入数据
                    {
                        long contentLength = fs.Length;//获取下载文件的大小
                        Response.ContentLength = contentLength;//在Response的Header中设置下载文件的大小,这样客户端浏览器才能正确显示下载的进度
    
                        byte[] buffer;
                        long hasRead = 0;//变量hasRead用于记录已经发送了多少字节的数据到客户端浏览器
    
                        //如果hasRead小于contentLength,说明下载文件还没读取完毕,继续循环读取下载文件的内容,并发送到客户端浏览器
                        while (hasRead < contentLength)
                        {
                            //HttpContext.RequestAborted.IsCancellationRequested可用于检测客户端浏览器和ASP.NET Core服务器之间的连接状态,如果HttpContext.RequestAborted.IsCancellationRequested返回true,说明客户端浏览器中断了连接
                            if (HttpContext.RequestAborted.IsCancellationRequested)
                            {
                                //如果客户端浏览器中断了到ASP.NET Core服务器的连接,这里应该立刻break,取消下载文件的读取和发送,避免服务器耗费资源
                                break;
                            }
    
                            buffer = new byte[bufferSize];
    
                            int currentRead = fs.Read(buffer, 0, bufferSize);//从下载文件中读取bufferSize(1024字节)大小的内容到服务器内存中
    
                            Response.Body.Write(buffer, 0, currentRead);//发送读取的内容数据到客户端浏览器
                            Response.Body.Flush();//注意每次Write后,要及时调用Flush方法,及时释放服务器内存空间
    
                            hasRead += currentRead;//更新已经发送到客户端浏览器的字节数
                        }
                    }
                }
    
                return new EmptyResult();
            }
        }
    }
  • 相关阅读:
    软考相关网站汇总
    教育界常用网站汇总
    vue实现选中li变色--小技巧
    vue前端路由的两种模式,hash与history的区别
    element中级联选择器动态加载数据 递归的思想(数据量过于庞大,后端不一次性把数据返回)
    关于echarts和高德地图使用的一些小细节
    Vue中的$set的使用 (为对象设置属性)
    高德地图根据地址获取经纬度
    vue强制刷新组件 (用keep-alive怎么都不生效,可能是因为这是组件,没涉及到路由),相当于每次重新初始化组件
    webpack
  • 原文地址:https://www.cnblogs.com/OpenCoder/p/10013240.html
Copyright © 2011-2022 走看看