在上一節中我們學習瞭在java中學習多線程下載的基本原理和基本用法,我們並沒有講多線程的斷點續傳,那麼這一節我們就接著上一節來講斷點續傳,斷點續傳的重要性不言而喻,可以不用重復下載,也可以節省時間,實現斷點續傳的關鍵在於怎麼記錄下載的進度和怎麼標識,現在我們就來講一下。
簡言之就是:為每個線程開辟一個文件,分別來記錄每個線程的下載進度,在每個線程下載之前判斷這個標記文件是否存在,如果存在讀取相應文件裡面的數據,並將下載文件的線程設置到相應的下載點即可。
這一節的代碼和上一節其實差不多,僅僅就是多瞭標記下載進度的一段代碼。現在我們一起來看看吧。
這段代碼就是在下載線程中去判斷每個線程的記錄下載進度的文件是否存在,如果存在則讀取裡面的進度。並把startIndex的值設置到相應的數據。
接著就是上述標記下載進度的文件是怎麼生成的,在哪裡生成的呢?代碼如下:
這個記錄文件的生成就是在下載的文件寫入到本地的過程中來標記生成的。
最後就是在所有線程結束後,把標記每個線程下載進度的文件刪除。記住:實在所有線程結束後一起刪除,並不是在每個下載線程運行完後就刪除。為什麼是所有線程完後再刪除呢?自己考慮吧,我就不解釋瞭!vcD4KPHA+PGltZyBzcmM9″https://www.aiwalls.com/uploadfile/Collfiles/20140104/20140104132929233.jpg” alt=”\”>
這就是刪除標記文件的操作。到這裡的解釋就完瞭,懂瞭嗎?
現在我把完整代碼貼出來,跟大傢共享,代碼如下:
package net.loonggg.test; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; public class MutilDownloader { // 開啟的線程的個數 public static final int THREAD_COUNT = 3; public static int runningThread = 3;// 記錄正在運行的下載文件的線程數 public static void main(String[] args) throws Exception { String path = "文件下載地址"; // 1、連接服務器,獲取一個文件,獲取文件的長度,在本地創建一個大小跟服務器文件大小一樣的臨時文件 URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5000); conn.setRequestMethod("GET"); int code = conn.getResponseCode(); if (code == 200) { // 服務器返回的數據的長度,實際就是文件的長度 int length = conn.getContentLength(); System.out.println("----文件總長度----" + length); // 在客戶端本地創建出來一個大小跟服務器端文件一樣大小的臨時文件 RandomAccessFile raf = new RandomAccessFile("temp.apk", "rwd"); // 指定創建的這個文件的長度 raf.setLength(length); // 關閉raf raf.close(); // 假設是3個線程去下載資源 // 平均每一個線程下載的文件的大小 int blockSize = length / THREAD_COUNT; for (int threadId = 1; threadId 0) { FileInputStream fis = new FileInputStream(tempFile); byte[] temp = new byte[1024 * 10]; int leng = fis.read(temp); // 已經下載的長度 String downloadLen = new String(temp, 0, leng); int downloadInt = Integer.parseInt(downloadLen); startIndex = downloadInt; fis.close(); } URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url .openConnection(); conn.setRequestMethod("GET"); // 重要:請求服務器下載部分的文件 指定文件的位置 conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex); conn.setConnectTimeout(5000); // 從服務器請求全部資源的狀態碼200 ok 如果從服務器請求部分資源的狀態碼206 ok int code = conn.getResponseCode(); System.out.println("---code---" + code); InputStream is = conn.getInputStream();// 已經設置瞭請求的位置,返回的是當前位置對應的文件的輸入流 RandomAccessFile raf = new RandomAccessFile("temp.apk", "rwd"); // 隨機寫文件的時候從哪個位置開始寫 raf.seek(startIndex);// 定位文件 int len = 0; byte[] buffer = new byte[1024]; int total = 0;// 記錄已經下載的數據的長度 while ((len = is.read(buffer)) != -1) { RandomAccessFile recordFile = new RandomAccessFile(threadId + ".txt", "rwd");// 記錄每個線程的下載進度,為斷點續傳做標記 raf.write(buffer, 0, len); total += len; recordFile.write(String.valueOf(startIndex + total) .getBytes()); recordFile.close(); } is.close(); raf.close(); System.out.println("線程:" + threadId + "下載完畢瞭!"); } catch (Exception e) { e.printStackTrace(); } finally { runningThread--; if (runningThread == 0) {// 所有的線程已經執行完畢 for (int i = 1; i <= THREAD_COUNT; i++) { File file = new File(i + ".txt"); file.delete(); } } } } } }