这个是下载的工具类,改编自网上找到的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"); } }