public class MutiThradDownload {
//使用3条线程去下载
private static int threadCount = 3;//你要不要多少个下载的线程同时下载
private static String path = "http://192.168.10.157:8080/QQ.apk";//地址
public static void main(String[] args) {
//向服务器发请求,要下载的长度是多少
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
int code = conn.getResponseCode();
if (code==200) {
int lenth = conn.getContentLength();
File file = new File(getFilename(path));//截取后缀部分最后文件名
RandomAccessFile raf = new RandomAccessFile(file,"rw");//文件类型为读写模式
raf.setLength(lenth);//设置文件的大小和目标文件大小一致
raf.close();
//每块线程下载的大小
int blockSize = lenth/threadCount;//确定每个线程下载的大小
System.out.println("文件总大小为"+lenth);
for (int threadId = 0; threadId < threadCount; threadId++) {
int startIndex = threadId*blockSize;
int endIndex = (threadId+1)*blockSize-1;
if (threadId==threadCount-1) {//用if来判断是否是最后一个线程,如果是则最后一个线程的结束就是文件的大小
endIndex = lenth-1;
}
new DownloadPart(threadId, startIndex, endIndex).start();//开启线程准备下载
// System.out.println("第"+threadId+"线程:从"+startIndex+"~"+endIndex);
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static class DownloadPart extends Thread{
private int threadId; //线程ID
private int startIndex; //线程开始的索引
private int endIndex; //线程结束的索引
private int currentPosition;//当前位置下载的位置
public DownloadPart (int threadId,int startIndex,int endIndex){
this.threadId = threadId;
this.startIndex = startIndex;
this.endIndex = endIndex;
this.currentPosition = startIndex;//第一次进来的时候线程当前的下载位置就是开始位置
}
@Override
public void run() {
System.out.println("第"+threadId+"线程:开始下载了"+startIndex+"~"+endIndex);
//在这里干下载的事情,下载目标的部分的数据
try {
URL url= new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
File file = new File(getFilename(path));
RandomAccessFile raf = new RandomAccessFile(file, "rw");//随机读写的一个类在多线程下载里面很是重要
conn.setRequestProperty("range", "bytes="+startIndex+"-"+endIndex);//这个Connection里面的一个很重要的方法通过这个方法我们可以向服务器发送请求,所需要的数据
System.out.println("----"+threadId);
File ilf = new File(threadId+".position");
if (ilf.exists()&&ilf.length()>0) {//如果问价存在的话说明之前就已经下载过了 此时的开始索引就会有所改变
System.out.println("之前下载过");
BufferedReader br = new BufferedReader(new FileReader(ilf));
String vl = br.readLine();
int alreadlywriteposition = Integer.parseInt(vl);
//从这个位置开始要
conn.setRequestProperty("range", "bytes="+alreadlywriteposition+"-"+endIndex);
raf.seek(alreadlywriteposition);//
}else{
System.out.println("之前没有下载过");
conn.setRequestProperty("range", "bytes="+startIndex+"-"+endIndex);
raf.seek(startIndex);
}
//获得返回的目标端的数据
int code = conn.getResponseCode();
if (code==206) {
InputStream in = conn.getInputStream();
int len = 0 ;
byte[] buf = new byte[1024];
while ((len=in.read(buf))>0) {
raf.write(buf,0,len);
//将实时的位置及记录了下来
currentPosition = currentPosition+len;//没下载一点都会保存下来,下次继续下载的时候会根据这个值来判断从哪里开始下载
File info = new File(threadId+".position");//保存到一个文件里面
OutputStream out = new FileOutputStream(info);
out.write(String.valueOf(currentPosition).getBytes());
out.close();
}
raf.close();
in.close();
}
System.out.println("第"+threadId+"线程下载结束了");
//下载结束后将记录的文件删掉
synchronized (MutiThradDownload.class) {
currentcount--;
if (currentcount<=0){
//所有的线程都下载完了,将就下载的文件都删掉
File fff = new File(threadId+".position");
fff.renameTo(new File(threadId+".position"));
for (int threadid = 0; threadid <threadCount; threadid++) {
File fll = new File(threadId+".position");
fll.delete();
}
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static String getFilename(String path){
int index = path.lastIndexOf("/");
return path.substring(index+1);
/**
* 解释下substring这个方法,他表示的是从当前位置到字符串末尾截取的字符串
* 这里是以/为届,最后一个索引截取,在index加一表示从下一个位置开始获得
*/
}
}
多线程下载,断点续传
最新推荐文章于 2024-03-10 23:38:03 发布