说到文件下载,就不能不说断点续传,大家可能用过在网页中借助Flash来实现下载进度显示的工具,这个工具只适用于文件体积不是很大的时候,用户可以非常有保障的在一定的时间内下载完成,一旦下载进程中断(网络或其它原因),用户就不得不从头开始下载文件,这对于大文件体积的情况(比如视频),就会很麻烦,用户可能下载了几十MB的时候,突然网络断了,然后只能从头再来,这是非常差的体验。那么能否通过Flash技术,实现断点续传呢?我们先来探讨一下断点续传的原理。
断点续传的原理
现在基本上任何一个下载工具都是支持断点续传的,抛开P2P的成分不谈,我们单说通过HTTP服务器是如何实现断点续传的。关键在于你向HTTP服务器发起文件请求的时候,是否明确的告知,要下载文件的哪个区域,我们都知道HTTP请求是有一个Header的,实际上里面有个属性是定义下载的区域的,这个属性就是Range,它接收的值是一个区间范围,比如:
Range:bytes=0-10000
这样我们就可以按照一定的规则,将一个大文件拆分为若干很小的部分,然后分批次的下载,每个小块下载完成之后,都合并到文件中,这样即时中间中断了下载,我们重新开始下载的时候,也可以通过文件的字节长度来判断下载的起始点,然后重启断点续传的过程,直到最后完成下载过程。
在AS3中,我们是可以为URLRequest添加HTTP头的,就是URLRequestHeader。基于这一点,我们可以说,只需要Flash Player我们其实已经可以实现断点续传了,但问题在于Flash Player是不能自动保存本地文件的,也就是说我们整个断点续传的过程只能在内存里完成,一旦页面刷新,电脑重启,还是要从0开始下载,实际意义不大。
而AIR运行时的出现又为我们保存本地文件提供了可能,所以我们完全可以基于AS3+Flash Player+AIR,制作一个断点续传的工具。
实现过程
实现的主要几个要点:
- 首先对文件发起请求,得到文件的尺寸(字节长度),但并不下载
- 然后将文件划分为若干区域,对第一个区域的内容发起请求(通过指定HTTP头的Range)
- 第一个区域的内容很快下载完成,使用File保存到本地文件
- 移动指针,对第二个区域的内容发起请求,下载完毕后与文件合并
- 以此类推,直到下载完成整个文件
主要代码片段:
- 先发送一个下载请求,可以得到文件的真实尺寸
-
getContentLengthLoader. addEventListener ( ProgressEvent. PROGRESS , function (e : ProgressEvent ) : void {
-
contentLength = getContentLengthLoader. bytesTotal; //得到文件的真实尺寸
-
getContentLengthLoader. close ( ); //停止下载
-
downloadByRange ( ); //按照断点续传的方式下载
-
} );
-
getContentLengthLoader. load (getContentLengthRequest );
- 计算已下载的部分的字节长度
-
if (file.exists ) { //如果文件是存在的,就说明下载过,需要计算从哪个点开始下载
-
fileStr. open (file, FileMode.READ );
-
startPoint = fileStr. bytesAvailable; //计算从哪个点开始下载
-
fileStr. close ( ); //关闭文件流
-
}
-
- 为请求的Header添加Range
-
var header : URLRequestHeader = new URLRequestHeader ( "Range", "bytes=" +startPoint + "-" +endPoint ); //注意这里很关键,我们在请求的Header里包含对Range的描述,这样服务器会返回文件的某个部分
-
rangeRequest. requestHeaders. push (header ); //将头信息添加到请求里
- 保存文件
-
fileStr = new FileStream ( );
-
fileStr. open (file, FileMode.UPDATE );
-
fileStr. position = fileStr. bytesAvailable; //将指针指向文件尾
-
fileStr. writeBytes (currentData, 0, currentData. length ); //在文件中写入新下载的数据
-
fileStr. close ( ); //关闭文件流
-
完整代码查看以及下载:
http://www.riameeting.com/examples/end_point_download/
然后测试,你可以看到下载进度,也可以在下载的过程中点击暂停,甚至关闭应用,重新启动,都可以从断点开始下载文件