这个是下载的工具类,改编自网上找到的annegu兄的代码,这位仁兄是多线程断点,但是我这里不需要断点,所以做了简化。
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
*
*
*/
public class DownloadUtil {
private static final Log log = LogFactory.getLog(DownloadUtil.class);
private int threadNum = 5;
private String urlStr;
private File file = null;
private AtomicBoolean statusError = new AtomicBoolean(false);
private long sleepSeconds = 5;
public DownloadUtil(String url, File file, int threadNum) {
this(url, file, threadNum, 5);
}
public DownloadUtil(String url, File file, int threadNum, long sleepSec) {
this.urlStr = url;
this.file = file;
if (threadNum > 0) {
this.threadNum = threadNum;
}
if (sleepSec > 0) {
this.sleepSeconds = sleepSec;
}
}
public boolean download() {
log.info("download the file " + file.getName() + " from " + urlStr);
CountDownLatch latch = new CountDownLatch(threadNum);//这个是亮点
try {
file.createNewFile();
HttpURLConnection con = (HttpURLConnection) new URL(urlStr).openConnection();
setHeader(con);//这里是伪造头信息
long contentLength = con.getContentLength();
long threadLength = contentLength / threadNum;
ExecutorService exec = Executors.newCachedThreadPool();
for (int i = 0; i < threadNum; i++) {
long end = threadLength * (i + 1) - 1;
if (i == threadNum - 1) {
end = contentLength;
}
ChildThread thread = new ChildThread(this, latch, i,
threadLength * i, end);
exec.execute(thread);
}
try {
latch.await();
exec.shutdown();
if (file.length() != contentLength) {
log.warn("file download failed,because the size is not correct");
return false;
}
return true;
} catch (InterruptedException e) {
log.error(e.getMessage(), e);
}
} catch (IOException e) {
log.error(e.getMessage(), e);
}
return false;
}
private class ChildThread implements Runnable {
private DownloadUtil task;
private int id;
private long startPosition;
private long endPosition;
private final CountDownLatch latch;
private RandomAccessFile file = null;
public ChildThread(DownloadUtil task, CountDownLatch latch, int id,
long startPos, long endPos) {
super();
this.task = task;
this.id = id;
this.startPosition = startPos;
this.endPosition = endPos;
this.latch = latch;
try {
file = new RandomAccessFile(task.file, "rw");
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
public void run() {
log.info("Thread " + id + " run ...");
HttpURLConnection con = null;
InputStream inputStream = null;
for (;;) {
try {
con = (HttpURLConnection) new URL(task.urlStr).openConnection();
setHeader(con);
// 设置连接超时时间为10000ms
con.setConnectTimeout(10000);
// 设置读取数据超时时间为10000ms
con.setReadTimeout(10000);
if (startPosition < endPosition) {
// 设置下载数据的起止区间
con.setRequestProperty("Range", "bytes=" + startPosition + "-" + endPosition);
log.debug("Thread " + id + " startPosition is " + startPosition + ", and endPosition is " + endPosition);
file.seek(startPosition);
// 判断http status是否为HTTP/1.1 206 Partial Content或者200 OK
// 如果不是以上两种状态,把status改为STATUS_HTTPSTATUS_ERROR
if (con.getResponseCode() != HttpURLConnection.HTTP_OK && con.getResponseCode() != HttpURLConnection.HTTP_PARTIAL) {
log.info("Thread " + id + ": code = " + con.getResponseCode() + ", status = " + con.getResponseMessage());
task.statusError.set(true);
file.close();
con.disconnect();
log.info("Thread " + id + " finished.");
latch.countDown();
break;
}
inputStream = con.getInputStream();
int len = 0;
byte[] b = new byte[1024];
while (!task.statusError.get() && (len = inputStream.read(b)) != -1) {
file.write(b, 0, len);
startPosition += len;
}
file.close();
inputStream.close();
con.disconnect();
}
log.info("Thread " + id + " finished.");
latch.countDown();
break;
} catch (IOException ex) {
// log.error(ex.getMessage(), ex);
try {
TimeUnit.SECONDS.sleep(task.sleepSeconds);
} catch (InterruptedException e) {
log.error(e.getMessage(), e);
}
continue;
}
}
}
}
private void setHeader(URLConnection con) {
con.setRequestProperty(
"User-Agent",
"Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.0.3");
con.setRequestProperty("Accept-Language", "en-us,en;q=0.7,zh-cn;q=0.3");
// con.setRequestProperty("Accept-Encoding", "aa");
con.setRequestProperty("Accept-Charset",
"ISO-8859-1,utf-8;q=0.7,*;q=0.7");
con.setRequestProperty("Keep-Alive", "300");
con.setRequestProperty("Connection", "keep-alive");
con.setRequestProperty("If-Modified-Since",
"Fri, 02 Jan 2009 17:00:05 GMT");
con.setRequestProperty("If-None-Match", "\"1261d8-4290-df64d224\"");
con.setRequestProperty("Cache-Control", "max-age=0");
// con.setRequestProperty("Referer",
// "http://www.skycn.com/soft/14857.html");
}
}