package cn.xl.c3; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import cn.xl.c3.DownloadTask.ChildThread; import cn.xl.c3.api.Connection; import cn.xl.c3.api.ConnectionException; import cn.xl.c3.api.ConnectionManager; import cn.xl.c3.api.DownloadListener; public class FileDownloader { private String url; private String fileName; private int threadLength; private String fileDir; private static final int DOWNLOAD_TRHEAD_NUM = 4; private DownloadThread[] childThreads ; DownloadListener listener; ConnectionManager cm; public FileDownloader(String _url,String _fileDir) { this.url = _url; this.fileDir = _fileDir; } public void execute(){ CyclicBarrier barrier = new CyclicBarrier(DOWNLOAD_TRHEAD_NUM , new Runnable(){ public void run(){ listener.notifyFinished(); } }); Connection conn = null; int[] startPos = new int[DOWNLOAD_TRHEAD_NUM]; CountDownLatch latch = new CountDownLatch(DOWNLOAD_TRHEAD_NUM); childThreads = new DownloadThread[DOWNLOAD_TRHEAD_NUM]; int endPos = 0; this.fileName = url.substring(url.lastIndexOf("/") + 1); try { conn = cm.open(this.url); int length = conn.getContentLength(); System.out.println("length===="+length); this.threadLength = length / DOWNLOAD_TRHEAD_NUM; ExecutorService exec = Executors.newCachedThreadPool(); // 第一步,分析已下载的临时文件,设置断点,如果是新的下载任务,则建立目标文件。在第4点中说明。 startPos = setThreadBreakpoint(fileDir, fileName, length, startPos); for (int i = 0; i < DOWNLOAD_TRHEAD_NUM; i++) { startPos[i] += threadLength * i; if (i == DOWNLOAD_TRHEAD_NUM - 1) { endPos = length; } else { endPos = threadLength * (i + 1) - 1; } DownloadThread downloadThread = new DownloadThread( fileDir+fileName, cm.open(this.url), i, startPos[i], endPos, latch); childThreads[i] = downloadThread; exec.execute(downloadThread); } try { latch.await(); exec.shutdown(); tempFileToTargetFile(childThreads); } catch (InterruptedException e) { e.printStackTrace(); } } catch (ConnectionException e) { e.printStackTrace(); }finally{ if(conn != null){ } } } private void tempFileToTargetFile(DownloadThread[] childThreads) { try { BufferedOutputStream outputStream = new BufferedOutputStream( new FileOutputStream(fileDir + fileName)); // 遍历所有子线程创建的临时文件,按顺序把下载内容写入目标文件中 for (int i = 0; i < DOWNLOAD_TRHEAD_NUM; i++) { /*if (statusError) { for (int k = 0; k < threadNum; k++) { if (childThreads[k].tempFile.length() == 0) childThreads[k].tempFile.delete(); } System.out.println("本次下载任务不成功,请重新设置线程数。"); break; } */ BufferedInputStream inputStream = new BufferedInputStream( new FileInputStream(childThreads[i].tempFile)); System.out.println("Now is file " + childThreads[i].id); int len = 0; int count = 0; byte[] b = new byte[1024]; while ((len = inputStream.read(b)) != -1) { count += len; outputStream.write(b, 0, len); if ((count % 5000) == 0) { outputStream.flush(); } // b = new byte[1024]; } inputStream.close(); childThreads[i].tempFile.delete(); // 删除临时文件 /*if (childThreads[i].status == ChildThread.STATUS_HAS_FINISHED) { childThreads[i].tempFile.delete(); } */ } outputStream.flush(); outputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private int[] setThreadBreakpoint(String fileDir2, String fileName2, int contentLength, int[] startPos) { File file = new File(fileDir + fileName); long localFileSize = file.length(); if (file.exists()) { System.out.println("file " + fileName + " has exists!"); // 下载的目标文件已存在,判断目标文件是否完整 if (localFileSize < contentLength) { System.out.println("Now download continue "); // 遍历目标文件的所有临时文件,设置断点的位置,即每个临时文件的长度 File tempFileDir = new File(fileDir); File[] files = tempFileDir.listFiles(); for (int k = 0; k < files.length; k++) { String tempFileName = files[k].getName(); // 临时文件的命名方式为:目标文件名+"_"+编号 if (tempFileName != null && files[k].length() > 0 && tempFileName.startsWith(fileName + "_")) { int fileLongNum = Integer.parseInt(tempFileName .substring(tempFileName.lastIndexOf("_") + 1, tempFileName.lastIndexOf("_") + 2)); // 为每个线程设置已下载的位置 startPos[fileLongNum] = (int) files[k].length(); } } } } else { // 如果下载的目标文件不存在,则创建新文件 try { file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } return startPos; } public void setListener(DownloadListener listener) { this.listener = listener; } public void setConnectionManager(ConnectionManager ucm){ this.cm = ucm; } public DownloadListener getListener(){ return this.listener; } }