一、首先建一个java项目,获取服务器上文件的大小,来确定多线程下载时,每个线程的开始和结束位置
static String path="http://192.168.1.141:8080/wps.exe";
public static void main(String[] args) {
// TODO Auto-generated method stub
//获取文件大小,计算每个线程下载的开始和结束位置
try {
//创建URL对象 指定我们要访问的网址
URL url = new URL(path);
//拿到httpurlconnection对象 用于发送和接受数据
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//设置请求超时时间
conn.setConnectTimeout(5000);//5秒
//设置发送请求方式
conn.setRequestMethod("GET");
//获取服务器返回的状态码
int code = conn.getResponseCode();
//200表明请求成功
if (code == 200) {
//获取服务器文件的大小
int length=conn.getContentLength();
System.out.println(length);
}
} catch (Exception e) {
e.printStackTrace();
}
}
二、创建一个大小和服务器一样的文件,提前把空间申请出来
RandomAccessFile randomAccessFile = new RandomAccessFile("temp.exe","rw");
randomAccessFile.setLength(length);
三、每个线程下载的开始与结束
假设3个线程下载10个字节的文件,每个线程a下载的大小为10/3,即a=10/3
第一个线程下载的开始和结束位置是 0*a------1*a-1j即(0-2)
第二个线程下载的开始和结束位置是 1*a------2*a-1j即(3-5)
第三个线程下载的开始和结束位置是 2*a------3*a-1j即(6-8)
剩余一个字节 3*a-------9 即(9-9)
从而得出第n个线程下载的开始和结束位置是n*a--------(n+1)*a-1
最后剩余m m*a--------length-1
1、申明变量线程的总数
private static final int threadCount=3;
2、每个线程下载的大小
int blockSize=length/threadCount;
3、计算每个线程下载的开始位置和结束位置
for (int i = 0; i < threadCount; i++) {
int startIndex=i*blockSize;
int endIndex=(i+1)*blockSize-1;
//特殊情况就是最后一个线程
if (i==threadCount-1) {
//说明最后一个线程
endIndex=length-1;
}
}
4、定义线程去服务器下载文件
private static class DownLoadThread extends Thread {
// 通过构造方法把每个线程下载的开始位置和结束位置传递进来
private int startIndex;
private int endIndex;
private int threadId;
public DownLoadThread(int startIndex, int endIndex, int threadId) {
this.startIndex = startIndex;
this.endIndex = endIndex;
this.threadId = threadId;
}
public void run() {
// 实现去服务器下载文件的逻辑
try {
// 创建URL对象 指定我们要访问的网址
URL url = new URL(path);
// 拿到httpurlconnection对象 用于发送和接受数据
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
// 设置请求超时时间
conn.setConnectTimeout(5000);// 5秒
// 设置发送请求方式
conn.setRequestMethod("GET");
// 设置一个请求头Range(告诉服务器每个线程下载的开始和结束位置)
conn.setRequestProperty("Range", "bytes=" + startIndex + "-"
+ endIndex);
// 获取服务器返回的状态码
int code = conn.getResponseCode();
// 200表明请求成功
if (code == 206) {// 请求部分资源
// 获取服务器返回的数据,返回的数据都是流的形式
// 创建随机读写文件对象
RandomAccessFile randomAccessFile = new RandomAccessFile(
"temp.exe", "rw");
// 每个线程从自己位置开始写
randomAccessFile.seek(startIndex);
InputStream in = conn.getInputStream();// 存的wps.exe
// 把数据写到文件中
int len = -1;
byte[] buffer = new byte[1024];
while ((len = in.read(buffer)) != -1) {
randomAccessFile.write(buffer, 0, len);
}
randomAccessFile.close();// 关闭流 释放资源
System.out.println("线程id:" + threadId);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
5、启动线程
DownLoadThread downLoadThread = new DownLoadThread(startIndex, endIndex, i);
downLoadThread.start();
四、断点续传
1、存储已下载的位置
int total=0;//当前线程下载的大小
total += len;
// 实现断点续传,就是把当前线程下载的位置 给存起来,下载再下载的时候 就是按照上次下载的位置继续下载就可以了
int currentThreadPosition = startIndex + total;//存到txt中
//用来存当前线程下的下载位置
RandomAccessFile raf = new RandomAccessFile(
"temp.exe", "rwd");
raf.write(String.valueOf(currentThreadPosition).getBytes());
raf.close();
2、判断是否下载过,读取位置,然后接着下载
File file=new File(threadId+".txt");
if (file.exists()&&file.length()>0) {
FileInputStream fis=new FileInputStream(file);
BufferedReader bufr=new BufferedReader(new InputStreamReader(fis));
String lastPosition=bufr.readLine();//读取出来的内容就是上一次下载的位置
int lastPositionn=Integer.parseInt(lastPosition);
startIndex=lastPositionn;
System.out.println("线程id:"+threadId+"真实下载的位置"+"---"+startIndex+"---"+endIndex);
fis.close();
}
3、删除因中断而产生的文件
在获取文件大小的时候设置变量runningThread=threadCount
synchronized (DownLoadThread.class) {
runningThread--;
if (runningThread==0) {
for (int i = 0; i < threadCount; i++) {
File deltFile=new File(i+".txt");
deltFile.delete();
}
}
}
五、一般下载到本地的文件名字和服务器名字一样
public static String getFilename(String path){
int start = path.lastIndexOf("/")+1;
return path.substring(start);
}
六、记得把上面的路径也都修改一下
项目源码:https://download.csdn.net/download/qq_35951882/10371245