多线成下载断点续传
1.了解一下多线程下载的思路
思路:开启多个线程下载同一个文件,这样可以使我们的下载文件的速度加快。如果我们使用单一的线程去下载。下载速度慢。
断点续传
1.断点续传需要在下载过程中记录每条线程的下载进度
2.每次下载开始之前先读取数据库,查询是否有未完成的记录,有就继续下载,没有则创建新记录插入数据库
3.在每次向文件中写入数据之后,在数据库中更新下载进度
4.下载完成之后删除数据库中下载记录
多线程下载的步骤
(1)首先获得下载文件的长度,然后设置本地文件的长度。
HttpURLConnection.getContentLength();//获取下载文件的长度
RandomAccessFile file = new RandomAccessFile(“QQWubiSetup.exe”,”rwd”);
file.setLength(filesize);//设置本地文件的长度
(2)根据文件长度和线程数计算每条线程下载的数据长度和下载位置。
如:文件的长度为6M,线程数为3,那么,每条线程下载的数据长度为2M,每条线程开始下载的位置如
例如10M大小,使用3个线程来下载,
线程下载的数据长度 (10%3 == 0 ? 10/3:10/3+1) ,第1,2个线程下载长度是4M,第三个线程下载长度为2M
下载开始位置:线程id*每条线程下载的数据长度 = ?
下载结束位置:(线程id+1)*每条线程下载的数据长度-1=?
(3)使用Http的Range头字段指定每条线程从文件的什么位置开始下载,下载到什么位置为止,
如:指定从文件的2M位置开始下载,下载到位置(4M-1byte)为止
代码如下:HttpURLConnection.setRequestProperty(“Range”, “bytes=2097152-4194303”);
(4)保存文件,使用RandomAccessFile类指定每条线程从本地文件的什么位置开始写入数据。
RandomAccessFile threadfile = new RandomAccessFile(“QQWubiSetup.exe “,”rwd”);
threadfile.seek(2097152);//从文件的什么位置开始写入数据
多线程下载断点续传的源码:
/**
* 开启线程的数量
*/
static int threadCount=3;
/**
* 访问下载的路径
*/
static String path="http://169.254.87.122:8080/baofeng.exe";
static int threadFinished=0;
public static void main(String[] args) {
try {
//创建URL对象 参数:设置路径
URL url=new URL(path);
//打开连接,通过强制类型转换HttpURLConnection
HttpURLConnection connection=(HttpURLConnection) url.openConnection();
//设置请求的方式
connection.setRequestMethod("GET");
//设置读取的时间
connection.setReadTimeout(5000);
//设置连接的时间
connection.setConnectTimeout(5000);
if (connection.getResponseCode()==200) {
//拿到要下载文件的大小
int length = connection.getContentLength();
//指定临时文件的路径和文件名
File file=new File(getFileName(path));
//创建随机存储文件对象
RandomAccessFile raf=new RandomAccessFile(file, "rwd");
//设置临时文件的大小和服务器的一模一样
raf.setLength(length);
//计算每个线程下载的字节数
int size=length/threadCount;
for (int i = 0; i <threadCount; i++) {
//计算3个线程的开始位置和结束位置
int startIndex=i*size;
int endIndex=(i+1)*size-1;
//如果是最后一个线程,那么结束位置特殊处理
if (i==threadCount-1) {
endIndex=length-1;
}
System.out.println("线程"+i+"-----------"+startIndex+"-------"+endIndex);
DowndLoadThread thread = new DowndLoadThread(i, startIndex, endIndex);
thread.start();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 得到文件名字的
* @param path 传入的访问的路径
* @return 返回处理后的结果
*/
public static String getFileName(String path){
//找到最后/的索引
int index = path.lastIndexOf("/");
//进行截取
return path.substring(index+1);
}
static class DowndLoadThread extends Thread{
int threadId;
int startIndex;
int endIndex;
/**
* 创建有参构造函数
* @param threadId 第几个线程的
* @param startIndex 开始的索引
* @param endIndex 结束的索引
*/
public DowndLoadThread( int threadId,int startIndex, int endIndex) {
super();
this.startIndex = startIndex;
this.endIndex = endIndex;
this.threadId = threadId;
}
@Override
public void run() {
super.run();
URL url;
try {
//设置线程从那个位置开始写入数据到临时文件
File fileProgress=new File("h://"+threadId+".txt");
//判断下载的临时文件是否存在
if (fileProgress.exists()) {
FileInputStream fis=new FileInputStream(fileProgress);
BufferedReader br=new BufferedReader(new InputStreamReader(fis));
//拿到临时文件所存储的位置
int newStartIndex = Integer.parseInt(br.readLine());
startIndex=newStartIndex;
System.out.println("线程"+threadId+"最终位置---------------"+startIndex);
}
url = new URL(path);
HttpURLConnection connection=(HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setReadTimeout(5000);
connection.setConnectTimeout(5000);
//设置请求数据的范围
connection.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);
if (connection.getResponseCode()==206) {
InputStream is = connection.getInputStream();
int len=0;
byte[] b=new byte[1024];
int total=0;
File file=new File("h://"+MuiltDownLoad.getFileName(path));
//创建随机文件的存储对象
RandomAccessFile raf=new RandomAccessFile(file, "rwd");
raf.seek(startIndex);
//记录当前下载进度
int currentPosition=startIndex;
while((len=is.read(b))!=-1){
//把下载下来的临时文件写入raf临时文件
raf.write(b, 0, len);
total+=len;
@SuppressWarnings("resource")
RandomAccessFile rafProgress=new RandomAccessFile(fileProgress, "rwd");
currentPosition=startIndex+total;
//把下载进度写入rafProgress临时文件,下一次下载时作为新的startIndex
rafProgress.write((currentPosition+"").getBytes());
System.out.println("线程"+threadId+"---------------"+total);
}
raf.close();
System.out.println("线程"+threadId+"下载完毕");
MuiltDownLoad.threadFinished++;
//如果这个条件成立,说明线程下载完毕
synchronized (MuiltDownLoad.path) {
if (MuiltDownLoad.threadFinished==MuiltDownLoad.threadCount) {
for (int i = 0; i < MuiltDownLoad.threadCount; i++) {
File temp=new File("h://"+i+".txt");
temp.delete();
}
MuiltDownLoad.threadFinished=0;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}