2019独角兽企业重金招聘Python工程师标准>>>

在本系列的前两篇文章中,分别向大家介绍了用于完成下载任务的 WebClinet 和 WinINet 的基本用法和一些实用技巧。

今天来为大家讲述下载过程中最常遇到的断点续传问题。

首先明确一点,本文所说的断点续传特指 HTTP 协议中的断点续传,文章中讲述了实现断点续传的方法思路和关键代码,想了解更多细节的同学,请下载并查看本文附带的 demo。


工作原理

http 协议中定义了一些请求/响应头,通过组合使用这些头信息,即可实现分批下载同一文件的目的。例如,在一次 http 请求中只请求文件中的一部分数据,然后将请求到的数据保存起来,下次只需请求剩余部分的数据,当全部数据都下载到本地后再完成数据的合并工作。

http 协议指出,可以通过 http 请求中的 Range 头来指定请求数据的范围。

Range 头的使用很简单,按照如下的格式使用即可:

Range: bytes=500-999

上述意思为:只请求目标文件的第500至第999,这500个字节。

举例说明,有一个1000 字节大小的文件需要下载,第一次请求时不指定 Range 头,表示下载整个文件;但在下载完第499个字节后,下载被中断了,那么在下一次请求剩余文件时,只需要下载第500个至第999个字节的数据即可。

原理看上去很简单,但是需要考虑以下几个问题:

1. 是不是所有的 web 服务器都支持 Range 头?

2. 多次请求之间可能会间隔很长的时间,服务器上的文件发生了变化怎么办?

3. 如何保存下载的部分数据和相关信息?

4. 当我们通过字节操作把一个文件拼成原始大小后,如何验证它和源文件是一模一样的?

接下来,本文分别针对以上问题,给出解决方法。


一、如何检查服务器端是否支持 Range头?

在服务器响应请求时,会在响应头中通过 Accept-Ranges 指明是否接受请求资源的一部分数据,这里似乎有个小问题,就是不同的服务器可能返回不同的值来指明是否接受下载部分资源的请求。比较统一的做法是:当服务器不支持请求部分数据时,都会返回 Accept-Ranges: none,所以只需判断返回值是否等于 none 就可以了。

代码如下:

private static bool IsAcceptRanges ( WebResponse res )

{

if ( res.Headers["Accept-Ranges"] != null )

{

string s = res.Headers["Accept-Ranges"];

if ( s == "none" )

{

return false;

}

}

return true;

}


二、如何检查服务器端的文件是否发生了变化?

当我们在下载文件的过程中,由于网络故障等原因中断了下载过程,这时如果服务器上的文件已经变化了,那么无论如何都需要重新从头开始下载,只有当服务器上的文件没有发生变化的情况下,断点续传才有意义。

当下次需要继续下载文件时,如何确定服务器上的文件还是当初下载了一半的文件?

对于这个问题,http 响应头为我们提供了两种选择,使用 ETag 和 Last-Modified 都能完成下载任务。

先看 ETag:

The ETag response-header field provides the current value of the entity tag for the requested variant. (引自RFC2616 14.19 ETag)

简单点说 ETag 就是一个标识当前请求内容的字符串,当请求的资源发生变化后,对应的 ETag 也会变化,所以最简单的办法是,第一次请求时把响应头中的 ETag 保存下来,下次请求时做相应的比较。

代码如下:

string newEtag = GetEtag( response );

// tempFileName指已经下载到本地的部分文件内容

// tempFileInfoName指保存了Etag内容的临时文件

if ( File.Exists(tempFileName) && File.Exists(tempFileInfoName) )

{

string oldEtag = File.ReadAllText( tempFileInfoName );

if ( !string.IsNullOrEmpty(oldEtag) && !string.IsNullOrEmpty(newEtag) && newEtag == oldEtag )

{

// Etag没有变化,可以断点续传

resumeDowload = true;

}

}

else

{

if ( !string.IsNullOrEmpty(newEtag) )

{

File.WriteAllText( tempFileInfoName, newEtag );

}

}

//GetEtag函数

private static string GetEtag( WebResponse res )

{

if ( res.Headers["ETag"] != null )

{

return res.Headers["ETag"];

}

return null;

}

再看 Last-Modified:

The Last-Modified entity-header field indicates the date and time at which the origin server believes the variant was last modified. (引自RFC2616 14.29 Last-Modified)

Last-Modified 就是所请求的资源在服务器上最后一次的修改时间,使用方法和 ETag 大体相同。

不论是使用 ETag 还是 Last-Modified,都能达到检测服务器端文件是否发生变化的目的。

当然也可以同时使用这两种方法,做 double check,以便更好的实现检测目的。


三、如何保存下载的部分数据和相关信息?

这里主要是指使用 C# 进行数据和相关信息的保存操作,大体思路是如果有未下载完的文件,先将已下载数据保存在某一路径下,然后将后下载的字节数据添加到已下载文件的末尾。

详细的实现方法,请查看 demo 代码。


四、如何验证下载文件与源文件的一致性?

在断点续传的过程中,我们以 byte 为单位进行文件的下载和合并,如果下载的整个过程中出现了异常,可能最后得到的文件就和源文件不一样了,因此最好能够对下载好的文件进行一次与源文件一致性的校验,这是很重要的一步,也是最难实现的部分。之所以难以实现,是因为需要服务器端的支持,例如要求服务器端不但提供了可供下载的文件,同时还需要提供该文件的 MD5 hush。

当然,如果服务器端也是我们自己创建的,我们就可以实现服务器端方面的支持。目前已有部分产品在下载过程中提供断点续传的能力,Spread Studio表格控件就是其中之一。

Demo 下载

转载于:https://my.oschina.net/powertoolsteam/blog/691675

Winform文件下载之断点续传相关推荐

  1. iOS 文件下载及断点续传

    ios的下载我们可以使用的方法有:NSData.NSURLConnection.NSURLSession还有第三方框架AFNetworking和ASI 利用NSData方法和NSURLConnecti ...

  2. android同时下载多个文件,android学习-多文件下载以及断点续传

    首先先感谢丰神,本文源于他的这篇微博http://blog.csdn.net/cfy137000/article/details/54838608,思路很棒,然后自己跟着代码撸了一遍,然后为了加深理解 ...

  3. RxJava+Retrofit+OkHttp深入浅出-终极封装四(多文件下载之断点续传)

    http://blog.csdn.net/wzgiceman/article/details/52911503 转载于:https://www.cnblogs.com/zhangminghan/p/6 ...

  4. Winform文件下载之WebClient

    最近升级了公司内部使用的一个下载小工具,主要提升了下面几点: 1. 在一些分公司的局域网中,连接不上外网 2. 服务器上的文件更新后,下载到的还是更新前的文件 3. 没有下载进度提示 4. 不能终止下 ...

  5. php 大文件下载,php超大文件下载及断点续传下载的实现代码

    $sourceFile = "jbxue.tmp"; //要下载的临时文件名 $outFile = "用户订单.xls"; //下载保存到客户端的文件名 $fi ...

  6. PHP实现文件下载断点续传详解

    如果我们的网站提供文件下载的服务,那么通常我们都希望下载可以断点续传(Resumable Download),也就是说用户可以暂停下载,并在未来的某个时间从暂停处继续下载,而不必重新下载整个文件. 通 ...

  7. php文件断点续传,PHP实现文件下载断点续传详解

    如果我们的网站提供文件下载的服务,那么通常我们都希望下载可以断点续传(Resumable Download),也就是说用户可以暂停下载,并在未来的某个时间从暂停处继续下载,而不必重新下载整个文件. 通 ...

  8. Android下载文件(一)下载进度断点续传

    Android下载文件(一)下载进度&断点续传 索引 Android下载文件(一)下载进度&断点续传 Android下载文件(二)单任务多线程并发&断点续传(待续) Andro ...

  9. java 断点续传 开源_java断点续传原理

    先说说断点续传的原理:这是HTTP 1.1协议的一部分,并不需要客户端特意去做多么复杂的事情.以前我曾经看过一个单位的技术标书,其中有下载的断点续传这一要求,给出的offer居然还挺高的... 简单的 ...

最新文章

  1. R语言ggplot2可视化:ggplot2可视化直方图(histogram)并在直方图的顶部外侧(top upper)或者直方图内部添加数值标签
  2. 【Windows 逆向】OD 调试器工具 ( CE 工具通过查找访问的方式找到子弹数据基地址 | 使用 OD 工具附加游戏进程 | 在 OD 工具中查看子弹数据地址 | 推荐 )
  3. php调取 zabbix实时数据_zabbix-基础系列(三)-zabbix安装[官方版]
  4. ps命令---Linux学习笔记
  5. 球体表面积原来还可以这么求!
  6. 【C++深度剖析教程17】逻辑操作符的陷阱
  7. Spring中,使用工具类无法自动注入service
  8. expected an indented block
  9. eclipse订制快捷键
  10. lable 标签右对齐
  11. 曾经我们无话不说,如今却渐渐形同陌路
  12. OCR:通用数码管图像识别训练和使用
  13. Charles的基本使用方法
  14. phpcms v9整站模板开发
  15. SPL 工业智能:识别指定工况
  16. DirectX12(D3D12)基础教程(十七)——让小姐姐翩翩起舞(3D骨骼动画渲染【2】)
  17. h5前端开发之js的学习1
  18. wifi密码忘了?电脑cmd一句搞定
  19. 使用bat脚本调用bandzip批量解压同密码的zip压缩包
  20. 官方2008年9月16日公布的不合格奶粉

热门文章

  1. Struts2中的ModelDriven机制及其运用、refreshModelBeforeResult属性解决的问题
  2. “C# 未在本地计算机上注册microsoft.Jet.OLEDB.12.0”的解决方案
  3. Office2010安装出现“错误1907”的解决方法(未验证)
  4. 解决 VMWARE MAC 10.12无法全屏的问题
  5. Google 已将“xxxx”标记为恶意扩展程序并阻止安装,解决方案
  6. 一个很小的图标需要另一个HTTP请求是不是很愚蠢? 如何将收藏夹图标放到精灵中?
  7. 如何生成MD5哈希?
  8. python全0序列_Python合集之Python序列(一)
  9. Matlab 变量保存csv:UnicodeDecodeError: ‘gbk‘ codec can‘t decode byte 0xfb in position 4: illegal multiby
  10. excel 单元格文本链接方法