上一篇的写法不适合大型档案下载,因为会一次配置整个档案所需的记忆体空间,并且档案完全载入后才输出到浏览器,这时如果档案大小超过 ASP.NET 可用的记忆体上限,就会出现错误造成档案下载失败。
当然要来证实一下XD,我先产生一个1GB的空白档案,然后下载看看。
产生空白档案的方法,开启 cmd 输入:fsutil file createnew test.txt 1073741824
fsutil file createnew 档案名称 档案大小 (单位为byte)
1KB = 1 x 1024 = 1024
1MB = 1 x 1024 x 1024 = 1048576
1GB = 1 x 1024 x 1024 x 1024 = 1073741824
执行档案下载后,程式出错了。
改善方式,不要一次配置整个档案的记忆体,只配置一小块缓冲区,每次读取档案只读取一部份到缓冲区,然后马上输出到浏览器,如此就可以用很少的记忆体完成大型档案下载的动作,程式码如下:
public class Download : IHttpHandler{ public void ProcessRequest(HttpContext context) { var index = context.Request.Params["index"]; var fileName = "test.txt"; //取得档案在 Server 上的实体路径 var filePath = context.Server.MapPath("~/File/" + fileName); //缓冲区大小,每次读取100KB var bufferSize = 102400; var buffer = new byte[bufferSize]; var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); //输出档案的位元组总长度 var outputLength = fs.Length; //每次读取的位元组长度 var readLength = 0; context.Response.Clear(); context.Response.AddHeader( "Content-Length", outputLength.ToString()); context.Response.ContentType = "application/octet-stream"; context.Response.AddHeader( "content-disposition", "attachment; filename=" + fileName); //剩余位元组长度大于零,且与浏览器连接着,就继续执行 while (outputLength > 0 && context.Response.IsClientConnected) { readLength = fs.Read(buffer, 0, bufferSize); context.Response.OutputStream.Write(buffer, 0, readLength); context.Response.Flush(); outputLength = outputLength - readLength; } fs.Close(); context.Response.End(); } public bool IsReusable { get { return false; } }}
结果:
相关文章:
[C#] ASP.NET 档案下载(1) - POST 和 GET 触发档案下载
[C#] ASP.NET 档案下载(2) - 大型档案下载
[C#] ASP.NET 档案下载(3) - 档案续传