HTML5技术

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

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

上面的方式我们发现,如果下载到一个半断网了下次会重头开始下载。这和我们今天的主题明显不符嘛。下面我们开始正式进入主题文件下载之断点续传。把前面我们说到的头属性Range用起来。 var request = new HttpReque

上面的方式我们发现,如果下载到一个半断网了下次会重头开始下载。这和我们今天的主题明显不符嘛。下面我们开始正式进入主题文件下载之断点续传。把前面我们说到的头属性Range用起来。

var request = new HttpRequestMessage { RequestUri = new Uri(url) }; request.Headers.Range = new RangeHeaderValue(rangeBegin, null); //【关键点】全局变量记录已经下载了多少,然后下次从这个位置开始下载。 var httpResponseMessage = await http.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);

完整代码:

/// <summary> /// 是否暂停 /// </summary> static bool isPause = true; /// <summary> /// 下载开始位置(也就是已经下载了的位置) /// </summary> static long rangeBegin = 0; //(当然,这个值也可以存为持久化。如文本、数据库等) private async void button3_ClickAsync(object sender, EventArgs e) { isPause = !isPause; if (!isPause)//点击下载 { button3.Text = "暂停"; await Task.Run(async () => { //异步操作UI元素 label1.Invoke((Action)(() => { label1.Text = "准备下载..."; })); long downloadSpeed = 0;//下载速度 using (HttpClient http = new HttpClient()) { var url = ":813/新建文件夹2.rar"; var request = new HttpRequestMessage { RequestUri = new Uri(url) }; request.Headers.Range = new RangeHeaderValue(rangeBegin, null); //【关键点】全局变量记录已经下载了多少,然后下次从这个位置开始下载。 var httpResponseMessage = await http.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); var contentLength = httpResponseMessage.Content.Headers.ContentLength;//本次请求的内容大小 if (httpResponseMessage.Content.Headers.ContentRange != null) //如果为空,则说明服务器不支持断点续传 { contentLength = httpResponseMessage.Content.Headers.ContentRange.Length;//服务器上的文件大小 } 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 && !isPause) { //使用追加方式打开一个文件流 using (FileStream fs = new FileStream(Application.StartupPath + "/temp.rar", FileMode.Append, FileAccess.Write)) { fs.Write(bytes, 0, writeLength); } downloadSpeed += writeLength; rangeBegin += 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)((rangeBegin) * 100 / contentLength), 1); })); } if (rangeBegin == contentLength) { label1.Invoke((Action)(() => { label1.Text = "下载完成"; })); } } } }); } else//点击暂停 { button3.Text = "继续下载"; label1.Text = "暂停下载"; } }

效果图:

到现在为止,你以为我们的断点续传就完成了吗?
错,你有没有发现我们使用的下载链接是a标签的。也就是我们自己写服务端提供的下载链接是不是也可以支持断点续传呢?下面我换个下载链接试试便知。

断点续传(服务端的支持)

测试结果如下:

发现并不支持断点续传。为什么a标签链接可以直接支持,我们写的下载却不支持呢。
a标签的链接指向的直接是iis上的文件(iis默认支持),而我们写的却没有做响应报文表头Range的处理。(没想象中的那么智能嘛 >_<)

前面我们说过,断线续传是HTTP的一个协议。我们遵守它,它就存在,我们不遵守它也就不存在。
那下面我们修改前面的文件下载代码(服务端):

public void FileDownload5() { //前面可以做用户登录验证、用户权限验证等。 string filename = "大数据.rar"; //客户端保存的文件名 string filePath = Server.MapPath("/App_Data/大数据.rar");//要被下载的文件路径 var range = Request.Headers["Range"]; if (!string.IsNullOrWhiteSpace(range))//如果遵守协议,支持断点续传 { var fileLength = new FileInfo(filePath).Length;//文件的总大小 long begin;//文件的开始位置 long end;//文件的结束位置 long.TryParse(range.Split('=')[1].Split('-')[0], out begin); long.TryParse(range.Split('-')[1], out end); end = end - begin > 0 ? end : (fileLength - 1);// 如果没有结束位置,那我们读剩下的全部 //表头 表明 下载文件的开始、结束位置 和文件总大小 Response.AddHeader("Content-Range", "bytes " + begin + "-" + end + "/" + fileLength); Response.ContentType = "application/octet-stream"; Response.AddHeader("Content-Disposition", "attachment;filename=" + filename); Response.TransmitFile(filePath, begin, (end - begin));//发送 文件开始位置读取的大小 } else { Response.ContentType = "application/octet-stream"; Response.AddHeader("Content-Disposition", "attachment;filename=" + filename); Response.TransmitFile(filePath); } }

然后再测试断点续传,完美支持。

多线程同时下载(分片下载)

 

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

网友点评
C