Winform文件下载之断点续传
在本系列的前两篇文章中,分别向大家介绍了用于完成下载任务的 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表格控件就是其中之一。
Winform文件下载之断点续传的更多相关文章
- 【SFTP】使用Jsch实现Sftp文件下载-支持断点续传和进程监控
参考上篇文章: <[SFTP]使用Jsch实现Sftp文件下载-支持断点续传和进程监控>:http://www.cnblogs.com/ssslinppp/p/6248763.html ...
- Winform文件下载之WinINet
在C#中,除了webclient我们还可以使用一组WindowsAPI来完成下载任务.这就是Windows Internet,简称 WinINet.本文通过一个demo来介绍WinINet的基本用法和 ...
- iOS开发之网络编程--4、NSURLSessionDataTask实现文件下载(离线断点续传下载) <进度值显示优化>
前言:根据前篇<iOS开发之网络编程--2.NSURLSessionDownloadTask文件下载>或者<iOS开发之网络编程--3.NSURLSessionDataTask实现文 ...
- iOS开发之网络编程--3、NSURLSessionDataTask实现文件下载(离线断点续传下载)
前言:使用NSURLSessionDownloadTask满足不这个需要离线断点续传的下载需求,所以这里就需要使用NSURLSessionDataTask的代理方法来处理下载大文件,并且实现离线断点续 ...
- iOS 文件下载及断点续传
ios的下载我们可以使用的方法有:NSData.NSURLConnection.NSURLSession还有第三方框架AFNetworking和ASI 利用NSData方法和NSURLConnecti ...
- 【转】iOS 文件下载及断点续传
ios的下载我们可以使用的方法有:NSData.NSURLConnection.NSURLSession还有第三方框架AFNetworking和ASI 利用NSData方法和NSURLConnecti ...
- C# 文件下载之断点续传
注意,本文所说的断点续传特指 HTTP 协议中的断点续传.本文主要聊聊思路和关键代码,更多细节请参考本文附带的 demo. 工作原理 HTTP 协议中定义了一些请求/响应头,通过组合使用这些头信息.我 ...
- php大文件下载支持断点续传
<?php /** php下载类,支持断点续传 * * Func: * download: 下载文件 * setSpeed: 设置下载速度 * getRange: ...
- Winform文件下载之WebClient
最近升级了公司内部使用的一个下载小工具,主要提升了下面几点: 1. 在一些分公司的局域网中,连接不上外网 2. 服务器上的文件更新后,下载到的还是更新前的文件 3. 没有下载进度提示 4. 不能终止下 ...
随机推荐
- Sql日期时间格式转换
sql server2000中使用convert来取得datetime数据类型样式(全) 日期数据格式的处理,两个示例: CONVERT(varchar(16), 时间一, 20) 结果:2007-0 ...
- Web调试利器OpenWindow
有些时候调试web页面,在循环里面我们不方便设置断点进行调试,或者调试起来比较麻烦,我们就可以用openWindow的方法打印出想要查看的信息,既方便又省时. 代码如下: OpenWindow = w ...
- js高阶函数
我是一个对js还不是很精通的选手: 关于高阶函数详细的解释 一个高阶函数需要满足的条件(任选其一即可) 1:函数可以作为参数被传递 2:函数可以作为返回值输出 吧函数作为参数传递,这代表我们可以抽离一 ...
- Dojo框架学习笔记<二>
一.dojo/dom 该模块定义了Dojo Dom API,主要有以下几种用法: 1.dom.byId();(相当于document.getElementById()) ①最直接的用 ...
- Oracle数据库备份 expdp/impdp导出导入命令
使用EXPDP和IMPDP时应该注意的事项: EXP和IMP是客户端工具程序,它们既可以在客户端使用,也可以在服务端使用. EXPDP和IMPDP是服务端的工具程序,他们只能在ORACLE服务端使用, ...
- JS无刷新分页插件
本文介绍一个本人自己写的一JS分页插件 <script src="/Js/smart.page.min.js" type="text/javascript" ...
- 我与solr(六)--solr6.0配置中文分词器IK Analyzer
转自:http://blog.csdn.net/linzhiqiang0316/article/details/51554217,表示感谢. 由于前面没有设置分词器,以至于查询的结果出入比较大,并且无 ...
- VMware Workstation虚拟机中的Linux通过NAT模式共享上网配置教程
VMware Workstation虚拟机中的Linux通过NAT模式共享上网配置教程 在VMware Workstation虚拟机下面,Linux虚机要上网,一般是桥接模式,但我自己的电脑上网的环境 ...
- 数据分析和R语言的那点事儿_1
最近遇到一些程序员同学向我了解R语言,有些更是想转行做数据分析,故开始学习R或者Python之类的语言.在有其他编程语言的背景下,学习R的语法的确是一件十分简单的事.霸特,如果以为仅仅是这样的话那就图 ...
- 第57讲:Scala中Dependency Injection实战详解
本讲我们来学习下依赖注入.让我们从代码出发: package scala.learn trait Logger {def log (msg:String)}trait Auth { auth:Log ...