工具类
public class DownUtil {
/**
* 下载路径
*/
private String path;
/**
* 保存路径
*/
private String saveFile;
/**
* 线程数量
*/
private int threadNum;
/**
* 文件下载大小
*/
private DownThread[] threads;
/**
* 文件大小
*/
private int fileSize;
public DownUtil(String path,String saveFile,int threadNum){
this.path=path;
this.threadNum=threadNum;
threads=new DownThread[threadNum];
this.saveFile=saveFile;
}
public void download(){
URL url;
HttpURLConnection con;
try {
url=new URL(path);
con= (HttpURLConnection) url.openConnection();
con.setConnectTimeout(5*1000);
con.setRequestMethod("GET");
con.setRequestProperty("Accept",
"image/gif,image/jpeg,image/pjpeg,image/pjpeg,"
+"application/x-shockwave-flash,application/xaml+xml"
+"application/vnd.ms-xpsdocument,application/xml-xbap"
+"application/x-ms-application,application/vnd.ms-excel"
+"application/vnd.ms-powerpoint,application/msword,*/*");
con.setRequestProperty("Accept-Language","zh-CN");
con.setRequestProperty("Charset","UFT-8");
con.setRequestProperty("Connection","Keep-Alive");
//文件大小
fileSize=con.getContentLength();
con.disconnect();
int currentPartSize=fileSize/threadNum+1;
RandomAccessFile file=new RandomAccessFile(saveFile,"rw");
//设置本地文件大小
file.setLength(fileSize);
file.close();
for (int i=0;i<threadNum;i++){
//计算每个线程下载的开始位置
int startPos=i*currentPartSize;
RandomAccessFile currentPart=new RandomAccessFile(saveFile,"rw");
//定位该线程的下载位置
currentPart.seek(startPos);
threads[i]=new DownThread(startPos,currentPartSize,currentPart);
threads[i].start();
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取下载进度
* @return
*/
public Double getCompleteRate(){
int sumSize=0;
for (int i=0;i<threadNum;i++){
sumSize+=threads[i].length;
}
return sumSize*1.0/fileSize;
}
class DownThread extends Thread{
/**
* 当前线程下载位置
*/
private int startPos;
/**
* 当前线程负责下载的大小
*/
private int currentPartSize;
/**
* 当前下载的文件块
*/
private RandomAccessFile currentPart;
/**
* 一下载的字节数
*/
public int length;
public DownThread(int startPos,int currentPartSize
,RandomAccessFile currentPart){
this.startPos=startPos;
this.currentPartSize=currentPartSize;
this.currentPart=currentPart;
}
HttpURLConnection con;
InputStream inputStream;
@Override
public void run(){
try {
URL url=new URL(path);
con= (HttpURLConnection) url.openConnection();
con.setConnectTimeout(5*1000);
con.setRequestMethod("GET");
con.setRequestProperty("Accept",
"image/gif,image/jpeg,image/pjpeg,image/pjpeg,"
+"application/x-shockwave-flash,application/xaml+xml"
+"application/vnd.ms-xpsdocument,application/xml-xbap"
+"application/x-ms-application,application/vnd.ms-excel"
+"application/vnd.ms-powerpoint,application/msword,*/*");
con.setRequestProperty("Accept-Language","zh-CN");
con.setRequestProperty("Charset","UFT-8");
inputStream=con.getInputStream();
//跳过startPos个字节,表明该线程只下载自己负责的那部分
inputStream.skip(this.startPos);
byte[] buffer=new byte[1024];
int hasRead=0;
//从网络读取数据,并写入到本地
while (length<currentPartSize&&(hasRead=inputStream.read(buffer))!=-1){
currentPart.write(buffer,0,hasRead);
//该线程下载的总大小
length+=hasRead;
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
currentPart.close();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
主类测试
public class Test2 {
public static void main(String[] args) {
final DownUtil downUtil = new DownUtil("https://www.python.org/ftp/python/3.10.2/python-3.10.2-amd64.exe"
, "d://python.exe", 4);
downUtil.download();
new Thread() {
@Override
public void run() {
Double rate = downUtil.getCompleteRate();
while (rate < 1) {
System.out.println("已完成 = " + rate);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
}