原文:http://www.cnblogs.com/warrior4236/p/5686404.html
一:需求分析
1:下载远程资源文件,通过多线程下载,达到高效的目的。
2:使用5个线程分别下载文件的不同部分。
二:定义成员变量以及初始化变量
// 定义成员变量
private String path; // 远程资源路径
private String targetPath; // 本地存储路径
private DownFileThread[] threads; // 线程list
private int threadNum; // 线程数量
private long length; // 下载的文件大小
// 构造初始化
public DownloadUtil(String path, String targetPath, int threadNum) {
super();
this.path = path;
this.targetPath = targetPath;
this.threads = new DownFileThread[threadNum];
this.threadNum = threadNum;
}
三:多线程下载文件
// 多线程下载文件资源
public void download() {
URL url;
try {
url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(5 * 1000); // 设置超时时间为5秒
conn.setRequestMethod("GET");
conn.setRequestProperty("connection", "keep-alive");
conn.setRequestProperty("accept", "*/*");
// 获取远程文件的大小
length = conn.getContentLength();
conn.disconnect();
// 设置本地文件大小
RandomAccessFile targetFile = new RandomAccessFile(targetPath, "rw");
targetFile.setLength(length);
// 每个线程下载大小
long avgPart = length / threadNum + 1;
// 下载文件
for (int i = 0; i < threadNum; i++) {
long startPos = avgPart * i;
RandomAccessFile targetTmp = new RandomAccessFile(targetPath,
"rw");
targetTmp.seek(startPos); // 分段下载
threads[i] = new DownFileThread(startPos, targetTmp, avgPart);
threads[i].start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
启动多个线程,每个线程下载文件的一部分,并发执行。
四:监控文件下载进度
// 监控下载进度
public double getDownRate() {
int currentSize = 0;
for (int i = 0; i < threadNum; i++) {
currentSize += threads[i].length;
}
return currentSize * 1.0 / length;
}
五:定义线程类
// 定义线程类
class DownFileThread extends Thread {
private long startPos;
private RandomAccessFile raf;
private long size;
private long length;
public DownFileThread(long startPos, RandomAccessFile raf, long size) {
super();
this.startPos = startPos;
this.raf = raf;
this.size = size;
}
public void run() {
URL url;
try {
url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
conn.setReadTimeout(5 * 1000); // 设置超时时间为5秒
conn.setRequestMethod("GET");
conn.setRequestProperty("connection", "keep-alive");
conn.setRequestProperty("accept", "*/*");
InputStream in = conn.getInputStream();
in.skip(this.startPos);
byte[] buf = new byte[1024];
int hasRead = 0;
while (length < size && (hasRead = in.read(buf)) != -1) {
raf.write(buf, 0, hasRead);
length += hasRead;
}
raf.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
六:测试多线程下载文件
public static void main(String[] args) {
String path = "http://localhost:8080/healthcare/html/HealthCare.war";
String targetPath = "D:/healthcare.war";
final DownloadUtil download = new DownloadUtil(path, targetPath, 4);
download.download();
// 主线程负责下载文件,在启动一个线程负责监控下载的进度
new Thread(new Runnable() {
@Override
public void run() {
while (download.getDownRate() < 1) {
System.out.println(download.getDownRate());
try {
Thread.sleep(200); // 200毫秒扫描一次
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}