HTML5技术

文件下载之断点续传(客户端与服务端的实现) - 农码一生(2)

字号+ 作者:H5之家 来源:H5之家 2017-07-31 18:00 我要评论( )

第四种:(Response.TransmitFile) 也就上开始举例说的那种,下载大文件也没有压力。【推荐】 public void FileDownload5(){//前面可以做用户登录验证、用户权限验证等。string filename = 大数据.rar; //客户端保

第四种:(Response.TransmitFile)
也就上开始举例说的那种,下载大文件也没有压力。【推荐】

public void FileDownload5() { //前面可以做用户登录验证、用户权限验证等。 string filename = "大数据.rar"; //客户端保存的文件名 string filePath = Server.MapPath("/App_Data/大数据.rar");//要被下载的文件路径 Response.ContentType = "application/octet-stream"; //二进制流 Response.AddHeader("Content-Disposition", "attachment;filename=" + filename); Response.TransmitFile(filePath); //将指定文件写入 HTTP 响应输出流 } 文件下载-客户端

上面实现了文件下载的服务端实现,接下来我们实现文件下载的客户端实现。客户端的下载可以直接是浏览器提供的下载,也可以是迅雷或者我们自己写的下载程序。这里为了更好的分析,我们来用winfrom程序自己写个下载客户端。

直接下载 private async void button1_ClickAsync(object sender, EventArgs e) { using (HttpClient http = new HttpClient()) { var httpResponseMessage = await http.GetAsync(":813/新建文件夹2.rar");//发送请求 (链接是a标签提供的) var contentLength = httpResponseMessage.Content.Headers.ContentLength;//读取文件大小 using (var stream = await httpResponseMessage.Content.ReadAsStreamAsync())//读取文件流 { var readLength = 1024000;//1000K 每次读取大小 byte[] bytes = new byte[readLength]; int writeLength; while ((writeLength = stream.Read(bytes, 0, readLength)) > 0)//分块读取文件流 { using (FileStream fs = new FileStream(Application.StartupPath + "/temp.rar", FileMode.Append, FileAccess.Write))//使用追加方式打开一个文件流 { fs.Write(bytes, 0, writeLength);//追加写入文件 contentLength -= writeLength; if (contentLength == 0)//如果写入完成 给出提示 MessageBox.Show("下载完成"); } } } } }

看着这么漂亮的代码,好像没问题。可现实往往事与愿违。

我们看到了一个异常“System.Net.Http.HttpRequestException:“不能向缓冲区写入比所配置最大缓冲区大小 2147483647 更多的字节。”,什么鬼,又是2147483647这个数字。因为我们下载的文件大小超过了2G,无法缓冲下载。
可是“缓冲下载”下又是什么鬼。我也不知道。那我们试试可以关掉这个东东呢?答案是肯定的。

var httpResponseMessage = await http.GetAsync(":813/新建文件夹2.rar");//发送请求

改成下面就可以了

var httpResponseMessage = await http.GetAsync(":813/新建文件夹2.rar",HttpCompletionOption.ResponseHeadersRead);//响应一可用且标题可读时即应完成的操作。 (尚未读取的内容。)


我们看到枚举HttpCompletionOption的两个值。一个是响应读取内容,一个是响应读取标题(也就是Headers里的内容)。

异步下载

我们发现在下载大文件的时候会造成界面假死。这是UI单线程程序的通病。当然,这么差的用户体验是我们不能容忍的。下面我们为下载开一个线程,避免造成UI线程的阻塞。

/// <summary> /// 异步下载 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void button2_ClickAsync(object sender, EventArgs e) { //开启一个异步线程 await Task.Run(async () => { //异步操作UI元素 label1.Invoke((Action)(() => { label1.Text = "准备下载..."; })); long downloadSize = 0;//已经下载大小 long downloadSpeed = 0;//下载速度 using (HttpClient http = new HttpClient()) { var httpResponseMessage = await http.GetAsync(":813/新建文件夹2.rar", HttpCompletionOption.ResponseHeadersRead);//发送请求 var contentLength = httpResponseMessage.Content.Headers.ContentLength; //文件大小 using (var stream = await httpResponseMessage.Content.ReadAsStreamAsync()) { var readLength = 1024000;//1000K byte[] bytes = new byte[readLength]; int writeLength; var beginSecond = DateTime.Now.Second;//当前时间秒 while ((writeLength = stream.Read(bytes, 0, readLength)) > 0) { //使用追加方式打开一个文件流 using (FileStream fs = new FileStream(Application.StartupPath + "/temp.rar", FileMode.Append, FileAccess.Write)) { fs.Write(bytes, 0, writeLength); } downloadSize += writeLength; downloadSpeed += writeLength; progressBar1.Invoke((Action)(() => { var endSecond = DateTime.Now.Second; if (beginSecond != endSecond)//计算速度 { downloadSpeed = downloadSpeed / (endSecond - beginSecond); label1.Text = "下载速度" + downloadSpeed / 1024 + "KB/S"; beginSecond = DateTime.Now.Second; downloadSpeed = 0;//清空 } progressBar1.Value = Math.Max((int)(downloadSize * 100 / contentLength), 1); })); } label1.Invoke((Action)(() => { label1.Text = "下载完成"; })); } } }); }

效果图:

断点续传

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • JS断点调试心得(转) - sunshinegirl_7

    JS断点调试心得(转) - sunshinegirl_7

    2016-04-20 14:00

  • js断点调试心得 - 沐清风blog

    js断点调试心得 - 沐清风blog

    2016-04-18 17:00

  • .NET C#微信公众号开发远程断点调试(本地远程调试生产环境代码) - 谁拿了我矿泉水

    .NET C#微信公众号开发远程断点调试(本地远程调试生产环境代码) - 谁

    2015-12-13 18:30

网友点评
>