您好,欢迎来到[编程问答]网站首页   源码下载   电子书籍   软件下载   专题
当前位置:首页 >> 编程问答 >> Java >> 发布一个多线程断点续传下载工具类给坛友使用

发布一个多线程断点续传下载工具类给坛友使用

来源:网络整理     时间:2016/7/25 4:33:55     关键词:

关于网友提出的“ 发布一个多线程断点续传下载工具类给坛友使用”问题疑问,本网通过在网上对“ 发布一个多线程断点续传下载工具类给坛友使用”有关的相关答案进行了整理,供用户进行参考,详细问题解答如下:

问题: 发布一个多线程断点续传下载工具类给坛友使用
描述:

本帖最后由 XYUUStudio 于 2013-05-08 18:47:20 编辑

欢迎测试下载,该类目前兼容泽元的ZCF框架,只需修改net.xyuu.eclipse.StringUtil为com.zving.framework.utility.StringUtil即可;
中间有部分校验已经删除,如若使用请保留版权申明,以便有bug请及时联系,统一修正,谢谢合作;
其实只用了一个字符串连接部分,原本我是使用+连接的,但是为了更严谨,所以使用的StringUtil.concat连接。完全基于jre环境,没有加入任何第三方类,可以用在任意java项目、android项目中。

public static String concat(Object... args) {
StringBuilder stringBuilder = null;
if (args.length > 0) {
stringBuilder = new StringBuilder();
}
for (int i = 0; i < args.length; i++) {
stringBuilder.append(args[i]);
}
return stringBuilder.toString();
}

代码中
System.out.println可自行删除,或者修改为项目所需的通知事件,
main方法为测试方法,实际使用中可删除;
需要的请直接看代码:

package net.xyuu.eclipse.service;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.util.concurrent.CountDownLatch;
import net.xyuu.eclipse.StringUtil;
/* 轩辕悠悠多线程断点续传下载类
 * XYUU FileDownloader Class
 * 作者:轩辕悠悠
 * Email&&QQ:xyuu@xyuu.net
 * 使用请保留该版权申明,以便有bug及时联系更新
 * 说明:字符串连接部分StringUtil.concat请使用项目所包含的工具类自行处理
 */
public class FileDownloader {
private CountDownLatch latch;
private Proxy proxy;
private String proxyAuthorization;
private String referer;
private URL url;
private RandomAccessFile tempfile;
private long[] beginPos;
private long[] endPos;
private long completeLength;
private long fileLength;
public void setProxyAuthorization(String proxyUser, String proxyPassword) {
this.proxyAuthorization = new sun.misc.BASE64Encoder().encode(StringUtil.concat(proxyUser, ":", proxyPassword).getBytes());
}
public void setProxy(String host, int port) {
this.proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port));
}
public void setProxy(Proxy proxy) {
this.proxy = proxy;
}
public void setReferer(String referer) {
this.referer = referer;
}
class DownloadThread extends Thread {
private int id;
public DownloadThread(int id) {
this.id = id;
}
public void run() {
HttpURLConnection conn = null;
BufferedInputStream bis = null;
try {
if (beginPos[id] < endPos[id]) {
byte[] buf = new byte[1024];
if (proxy == null)
conn = (HttpURLConnection) url.openConnection();
else {
conn = (HttpURLConnection) url.openConnection(proxy);
if (proxyAuthorization != null) {
conn.setRequestProperty("Proxy-Authorization", StringUtil.concat("Basic ", proxyAuthorization));
}
}
if (referer != null) {
conn.setRequestProperty("Referer", referer);
}
conn.setRequestProperty("Range", StringUtil.concat("bytes=", beginPos[id], "-", endPos[id]));
// 该条件可以去掉,只是做一个校验
// conn.setRequestProperty("Accept-Encoding", "identity");
// long proof = conn.getContentLength() - (endPos[id] - beginPos[id]);
// if (proof != 0 && proof != 1) {
// System.out.println("不支持多线程下载");
// latch.countDown();
// return;
// }
if (conn.getResponseCode() != 200 && conn.getResponseCode() != 206) {
System.out.println(StringUtil.concat("Responce Code:", conn.getResponseCode()));
run();
return;
}
bis = new BufferedInputStream(conn.getInputStream());
int len;
while ((len = bis.read(buf)) > 0) {
synchronized (tempfile) {
tempfile.seek(beginPos[id]);
tempfile.write(buf, 0, len);
beginPos[id] += len;
tempfile.seek(fileLength + 20 + id * 16);
tempfile.writeLong(beginPos[id]);
completeLength += len;
tempfile.seek(fileLength);
tempfile.writeLong(completeLength);
}
System.out.println(StringUtil.concat(completeLength * 100 / fileLength, "%"));
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (conn != null) {
conn.disconnect();
}
if (bis != null)
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
latch.countDown();
}
}
public void download(String address, String fileName, int threadCount) {
HttpURLConnection conn = null;
try {
url = new URL(address);
if (proxy == null)
conn = (HttpURLConnection) url.openConnection();
else {
conn = (HttpURLConnection) url.openConnection(proxy);
if (proxyAuthorization != null) {
conn.setRequestProperty("Proxy-Authorization", StringUtil.concat("Basic ", proxyAuthorization));
}
}
if (referer != null) {
conn.setRequestProperty("Referer", referer);
}
// conn.setRequestProperty("Accept-Encoding", "identity");
fileLength = conn.getContentLength();
// 服务器可能不支持断点续传或连接错误
if (fileLength <= 0) {
System.out.println("下载出错");
return;
}
File file = new File(fileName + ".tf");
tempfile = new RandomAccessFile(file, "rw");
beginPos = new long[threadCount];
endPos = new long[threadCount];
long tempFileLen = tempfile.length();
if (tempFileLen > fileLength) {
tempfile.seek(fileLength);
completeLength = tempfile.readLong();
long originalLen = tempfile.readLong();
if (originalLen != fileLength) {
System.out.println("文件长度不正确");
return;
}
threadCount = tempfile.readInt();
for (int i = 0; i < threadCount; i++) {
beginPos[i] = tempfile.readLong();
endPos[i] = tempfile.readLong();
}
address = tempfile.readUTF();
// referer = tempfile.readUTF();
} else {
completeLength = 0;
tempfile.seek(fileLength);
tempfile.writeLong(completeLength);
tempfile.writeLong(fileLength);
tempfile.writeInt(threadCount);
long packageLength = fileLength / threadCount;
long leftLength = fileLength % threadCount;
for (int i = 0; i < threadCount; i++) {
endPos[i] = beginPos[i] + packageLength;
if (leftLength > 0) {
endPos[i]++;
leftLength--;
}
tempfile.writeLong(beginPos[i]);
tempfile.writeLong(endPos[i]);
if (i + 1 < beginPos.length)
beginPos[i + 1] = endPos[i];
}
tempfile.writeUTF(address);
if (referer != null)
tempfile.writeUTF(referer);
}
latch = new CountDownLatch(threadCount);
System.out.println(fileLength);
for (int i = 0; i < threadCount; i++) {
new DownloadThread(i).start();
}
latch.await();
// 该条件可以去掉,只是为了做一个校验
// if (fileLength - completeLength != 1 - threadCount) {
// System.out.println("文件不完整");
// return;
// }
tempfile.setLength(fileLength);
tempfile.close();
file.renameTo(new File(fileName));
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (conn != null) {
conn.disconnect();
}
}
}
public static void main(String[] args) {
long time = System.currentTimeMillis();
FileDownloader fileDownload = new FileDownloader();
// fileDownload.setReferer("http://file.upengyou.com");
// http://9.duote.com.cn/fetionsmart.zip
fileDownload.download("http://dl.wandoujia.com/files/third/WanDouJiaSetup_pt_baidu67.exe", "D:\\WanDouJiaSetup_pt_baidu67.exe", 30);
System.out.println(System.currentTimeMillis() - time);
}
}

该类是我编写的一个eclipse自定义插件管理工具中使用的,主要用于插件下载时能支持断点续传(eclipse自带的插件管理工具居然不支持多线程断点续传,也不支持启动之前自行选择加载,我当时下一个400M的sdk,下载的时候啥都不能干,只能守在旁边干瞪眼,瞪了半个多小时,终于下到89%时,结果忽然掉线,一气之下打算自己动手写一个),所以包名为eclipse;
如果效果好,到时我会发布我的TheEclipse插件管理工具给广大坛友使用;
代码依然不够严谨,欢迎大神来喷,向我开炮吧!
以上介绍了“ 发布一个多线程断点续传下载工具类给坛友使用”的问题解答,希望对有需要的网友有所帮助。
本文网址链接:http://www.codes51.com/itwd/2903647.html

相关图片

相关文章