Java:断点续传

简介

我们下载文件或者其他内容时,常常都是通过Http协议直接请求整个文件。所以常见的方法是直接判断服务器返回的状态码,如果返回200,就开始写。所谓断点续传,就是指不请求整个文件,而是请求部分文件,如果服务器支持分段请求,则返回相应的分段内容,否则返回整个文件。我们可以通过断点续传来实现多条线程来下载同一个文件,加快速度;也可以通过断点续传实现暂停/恢复下载的功能,试想,如果没有断点请求,每次都是请求整个文件,又怎么能从上次暂停处恢复呢?


HTTP

和断点续传相关的HTTP内容主要有:

  • 断点请求头部
  • 206状态码

1、请求

当我们向服务器进行断点请求时,只需要在http请求上面添加下面的请求头部即可:

connection.setRequestProperty("Range", "bytes=0-");

Range头部有几种格式,注意是从0开始计数:
bytes=0-表示请求第0个字节到文件的最后一个字节;
bytes=10-100表示请求第10个字节到第100个字节;
bytes=-100表示请求第0个字节到第100个字节。

2、响应
我们在请求行加入上诉请求头部,这也是请求完整报文,但是与不加这个头部有什么不同呢?
如果服务器支持断点请求,此时返回的状态码是206,并且返回响应头部带有Content-Range=[bytes 0-6405598/6405599]的分段信息,很明显这个头部表示分段的请求区间以及整个文件的长度。
而如果服务器不支持断点请求时,返回的状态码是200,和普通的请求相同。
所以我们可以简单地通过状态码是否为206来判断服务器是否支持断点下载。


如果没有断点请求,我们一般都直接用FileOutputStream开始写整个文件了,不过既然是断点,那得写在特定的区间啊,可以通过RandomAccessFile来写特定区间。

randomAccessFile = new RandomAccessFile(savePath + saveName, "rw");
randomAccessFile.seek(startPos); 
while ((len = inputStream.read(buffer)) != -1){
    randomAccessFile.write(buffer, 0, len);
}

上诉片段代码就代表从startPos开始写内容


思路

一开始我们提到断点续传可以实现:

  • 多条线程来下载同一个文件,加快速度;
  • 暂停/恢复下载的功能。

这里基于服务器支持断点请求来讲一下多线程下载的思路,这个明白了暂停/恢复也是一回事。

假设我们请求的文件长度为len,需要n条线程来下载。大致步骤:
①计算每条线程的请求区间:

int segment = len / n;
for(int i = 0; i < n; i++){
    ranges[i].startPos = i * segment;  // Range数组,Range类有startPos和endPos两个属性
    ranges[i].endPos = startPos + segment - 1;
    if(i == n-1){
        ranges[i].endPos = len-1;
    }
}

②n条线程去请求

String range = "bytes=" + ranges[i].startPos + "-" + ranges[i].endPos;
connection.setRequestProperty("Range", range);

③写

randomAccessFile = new RandomAccessFile(savePath + saveName, "rw");
randomAccessFile.seek(ranges[i].startPos); // 先定位区间起始位置
while ((len = inputStream.read(buffer)) != -1){
    randomAccessFile.write(buffer, 0, len); // 开始写
}

这样我们就不再是请求整个文件,而是多条线程多个分段去下载了。


源码

上面只讲了多线程下载的思路,关于暂停恢复其关键点在于randomAccessFile.seek(startPos),只要记录好已下的长度,下次直接请求[已下,目的]长度,然后从已下的位置开始写即可。

基于断点续传写了一个小型的库,支持:
- 暂停下载
- 恢复下载
- 下载回调
- 通过回调获得下载任务的总长度、已下长度、耗时、进度、平均下载速度等…
- …

https://github.com/leelit/Downloader

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值