public class DownloadUtils {
// 完成的线程
private int completeThread;
private int threadCount;
/**
* 开始多线程下载
*
* @param url
* 访问的服务器地址
* @param dir
* 本地接收路径
* @param threadCount
* 开启多少条线程下载
*/
public void startMultiThreadDownload(final String url, final String dir,
final int threadCount) {
this.threadCount = threadCount;
completeThread = 0;
new Thread(new Runnable() {
@Override
public void run() {
// 1.请求服务器上的文件的长度
int fileLength = getRemoteServiceFileLength(url);
if (fileLength == -1) {
System.out.println("请求服务器文件长度失败,停止下载");
return;
}
System.out.println("远程服务器的长度为:" + fileLength);
// 2.根据服务器上的文件长度在手机上创建一个一模一样大小的文件
String fileName = url.substring(url.lastIndexOf("/") + 1);
File file = new File(dir, fileName);
try {
RandomAccessFile raf = new RandomAccessFile(file, "rwd");
raf.setLength(fileLength);
raf.close();
System.out.println("本地文件创建成功" + file.getPath());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 3.根据线程的个数和文件的长度来计算每一个线程需要下载的范围
int blockSize = fileLength / threadCount;
for (int i = 0; i < threadCount; i++) {
// 开始的位置:线程的id*每一块的大小。
int start = i * blockSize;
// 结束的位置:线程的(id+1 ) *每一块的大小 -1;
int end = (i + 1) * blockSize - 1;
// 最后一个线程结束的位置是:文件的长度-1;
if ((i == threadCount - 1)) {
end = fileLength - 1;
}
// 4.开启多个线程,每一个线程下载自己的那块范围,传递参数:下载地址,存储文件的路径
// 开始的位置,结束的位置,线程ID
new Thread(new DownloadRunnable(url, file.getPath(), start,
end, i)).start();
}
}
}).start();
}
/**
* 下载任务类
*
* @author Administrator
*
*/
class DownloadRunnable implements Runnable {
private String url;
private File localFile; // 文件的路径
private int start; // 当前线程开始下载的位置
private int end; // 结束下载的位置
private int threadID;// 线程ID
public DownloadRunnable(String url, String path, int start, int end,
int i) {
this.url = url;
this.localFile = new File(path);
this.start = start;
this.end = end;
this.threadID = i;
}
@Override
public void run() {
HttpURLConnection conn = null;
try {
// 添加断点下载
int total = 0;// 当前线程下载的总进度
// 把总进度值存储到本地去
File cacheFile = new File(localFile.getParent(), "thread"
+ threadID + ".hm");
RandomAccessFile cacheRAF = new RandomAccessFile(cacheFile,
"rwd");
// 判断上一次是否有缓存的进度
if (cacheFile.exists() && cacheFile.length() > 0) {// 文件存在并且有数据
// 上一次下载的进度
int progress = Integer.valueOf(cacheRAF.readLine());
start += progress;// 把上一次的进度在开始的位置加上,继续下载
total = progress;// 把上一次下载总进度赋值
}
System.out.println("线程" + threadID + ",开始下载了,下载的范围是:" + start
+ " ~" + end);
conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
// 设置请求头消息:Range,请求服务器上文件的部分内容
conn.setRequestProperty("Range", "bytes=" + start + "-" + end);
int responseCode = conn.getResponseCode();
if (responseCode == 206) {
int contentLength = conn.getContentLength();
System.out.println("线程" + threadID + ",请求成功,内容长度为:"
+ contentLength);
// 得到服务器返回的数据
InputStream is = conn.getInputStream();
RandomAccessFile raf = new RandomAccessFile(localFile,
"rwd");
// 把写入的位置移动到线程开始的位置上
raf.seek(start);
byte[] buf = new byte[1024];
int len = 0;
while ((len = is.read(buf)) != -1) {
raf.write(buf, 0, len);
total += len;
cacheRAF.seek(0);// 每一次都移动到文件的开始位置进行写入
cacheRAF.write(String.valueOf(total).getBytes());
}
cacheRAF.close();
raf.close();
is.close();
System.out.println("线程" + threadID + ",下载完成了.");
completeThread++;
if (completeThread == threadCount) {
System.out.println("全部下载完整,删除临时配置文件.");
for (int i = 0; i < threadCount; i++) {
File deleteFile = new File(localFile.getParent(),
"thread" + i + ".hm");
System.out.println(deleteFile.delete());
}
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (conn != null) {
conn.disconnect();
}
}
}
}
/**
* 根据URL连接请求远程服务器获取文件大小
*
* @param url
* 服务器地址
* @return
*/
private int getRemoteServiceFileLength(String url) {
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection) new URL(url).openConnection();
// 请求方式,必须大小
conn.setRequestMethod("GET");
// 连接超时
conn.setConnectTimeout(5000);
// 读取超时
conn.setReadTimeout(5000);
int reponseCode = conn.getResponseCode();// 获取的服务器返回的响应码
if (reponseCode == 200) {
return conn.getContentLength();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (conn != null) {
conn.disconnect();
}
}
return -1;
}
}
public class Demo {
public static void main(String[] args) {
System.out.println("开启多线程下载了............");
// 链接,路径,线程的数量
String url = "http://192.168.1.109/FeiQ.exe";
String dir = "F:/WDJDownload";
int threadCount = 3;
DownloadUtils du = new DownloadUtils();
du.startMultiThreadDownload(url, dir, threadCount);
}
}
原文地址:http://blog.csdn.net/a445012100/article/details/38523407