多线程断点续传
步骤拆分
1.下载文件
2.断点续传
3.多线程下载
4.多线程断点续传
下载文件
断点续传下载
步骤分解
推荐至少两个线程,当然也可以一个HttpURLConnection打开后,获取完文件长度,再关闭;然后再打开,然后设置文件数据范围
- 主线程:HttpURLConnection.getContentLengthLong() 获取文件大小
- 子线程:HttpURLConnection.setRequestProperty(“Range”, “bytes=” + filePos + “-“ + fileEnd) 获取文件数据范围
File.length()与HttpURLConnection.getContentLengthLong()比较文件大小
RandomAccessFile写入文件(如下)
1 | RandomAccessFile raf = new RandomAccessFile(fileDir, "rws"); |
实例
1 | package com.playgroud; |
普通文件下载
1 | public class DownloadTest { |
多线程下载
步骤分解
- 文件分块,与文件的起止下载位置
1、文件分块。 文件分块大小(blockSize)= (文件大小 +线程数 - 1 )/ 线程数 ;
2、确定每一个线程所要下载的 文件的起始和结束位置。
现假设为每个线程分别编号:0,1, 2,3;则
第一个线程负责的下载位置是: 0blockSize - (0+1) blockSize -1,
第二个线程负责的下载位置是: 1* blockSize - (1+1)blockSize -1,以此类推第i个线程负责的下载位置是:i blockSize - (i+1)blockSize -1;即线程(编号为id)下载开始位置 start = id block;
即线程(编号为id)下载结束位置 end = (id+1)*block -1;
- 线程同步:使用CountDownLatch同步各线程的任务,只有所有任务都完成了,才算执行完毕。
实例
核心代码
1 | package com.playgroud; |
测试程序
1 | public class playground { |
多线程断点续传
可以有两种实现形式:
- 有多少个线程就生成多少个文件,各自记录下载的起止位置,最后全部合并为一个文件(尝试失败,多个文件要处理比较复杂)
- 生成一个目标文件,生成一个(或根据线程数目)临时文件,在日志文件中记录各个线程的下载位置,则不需要合并文件,仅清除日志文件(推荐)
步骤分解
优雅结束进程,以便在临时文件中记录下载的进度、下载的线程数、下载大小等内容
- 写入一行,就记录一次位置,这样就不需要考虑优雅结束进程的问题;但是会导致部分数据丢失
- 一直写入,在接收到
interrupt的时候,再记录;不会丢失数据,但是处理逻辑更复杂(尝试) - 使用
Properties类来记录
文件合并(方式二)
文件一致性校验
迅雷链接的解析
- 迅雷的编码规则为:原地址前面加”AA”,后面加”ZZ”,然后进行Base64编码,最后加上迅雷下载协议”Thunder://“组成完整的下载链接
实例代码
1 | package com.playgroud; |
测试代码
1 | public class playground { |
改进:Web项目
#TODO#
下载速度、进度的显示
多个任务下,线程间速度的均摊
解析迅雷、BT链接
- 迅雷的编码规则为:原地址前面加”AA”,后面加”ZZ”,然后进行Base64编码,最后加上迅雷下载协议”thunder://“组成完整的下载链接
- BitTorrent Java实现
技术点总结
多线程断点续传
断点续传需要提供的能力:
RandomAccessFile类提供随机文件读取与写入的能力File类提供文件创建、计算长度的能力HttpURLConnection类提供访问http请求、查找数据资源范围的能力
多线程下载需要的能力:
ExecutorService类帮助进行线程管理CountDownLatch类帮助同步子线程任务进度相关公式帮助计算
- 单个线程的块大小:blockSize = (文件大小 +线程数 - 1 )/ 线程数 ;
- 下载的开始位置:start = id* block;
- 下载的结束位置:end = (id+1)*block -1;
多线程断点续传综合:
Properties类提供日志文件的读写能力,存放各个线程下载的信息
参考来源
断点续传相关
多线程相关
多线程断点续传
java如何实现BT下载