java 多執行緒檔案下載,斷點續傳
阿新 • • 發佈:2019-02-14
1,把阿里旺旺傳到伺服器上
2,分3個執行緒,分別下載不同位置的檔案
3,用3個檔案記錄每次下載的位置,停止後再次下載時,直接從已下載的位置開始繼續下載,當檔案下載完成後刪除記錄的檔案
測試成功,下面是實現程式碼:
package com.zhuyu.utils; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; /** * 多執行緒下載檔案 * @author zhuyu * 支援斷點續傳 */ public class MultiDownload { //執行緒數量 public static int threadCount = 3; //記錄執行緒下載檔案標識,所有執行緒下載完成則檔案下載完成 public static int runningThread = threadCount; public static void main(String[] args) throws MalformedURLException { //1.獲取檔案大小,建立一個和伺服器檔案對應的臨時檔案 //2.計算分配幾個執行緒下載伺服器資源,知道每個執行緒下載檔案的位置 //3.開啟多執行緒 開始位置:(執行緒id-1)* 每一塊大小 結束位置:(執行緒id* 每一塊大小)-1 String path = "http://192.168.20.117:8888/AliIM2014.exe"; URL url = new URL(path); try { String newFileName = path.substring(path.lastIndexOf("/") + 1); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5000); conn.setRequestMethod("GET"); int code = conn.getResponseCode(); if(code == 200){ //伺服器檔案總大小 int length = conn.getContentLength(); int blockSize = length / threadCount; //每一塊的大小 //在客戶端本地建立一個跟服務端大小一致的臨時檔案 RandomAccessFile raf = new RandomAccessFile(newFileName,"rwd"); raf.setLength(length); raf.close(); for(int threadId=1;threadId <= threadCount ; threadId ++){ int startIndex = (threadId - 1) * blockSize; int endIndex = (threadId * blockSize) - 1; if(threadId == threadCount){ //如果執行緒是最後一個,則結束位置為最後位置 endIndex = length ; } //下載檔案 new DownloadFileThread(path, startIndex, endIndex, threadId){}.start(); } }else{ System.out.println("請求失敗"); } } catch (Exception e) { e.printStackTrace(); } } public static class DownloadFileThread extends Thread { private String filepath; private int startIndex; private int endIndex; private int threadId; private String newFileName; public DownloadFileThread(String filepath, int startIndex, int endIndex,int threadId) { this.filepath = filepath; this.startIndex = startIndex; this.endIndex = endIndex; this.threadId = threadId; this.newFileName = filepath.substring(filepath.lastIndexOf("/") + 1); } @Override public void run() { try { //為支援斷點續傳,終止或異常發生時,儲存檔案下載的最後位置,下次繼續下載時讀取出來,從上次結束位置開始下載 //判斷是否存在已下載的檔案記錄,如果存在則開始位置 File file = new File(threadId + ".txt"); if(file.exists() && file.length() > 0){ String tempFileContent = txt2String(file); startIndex = Integer.parseInt(tempFileContent); } URL url = new URL(filepath); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);//請求資源的範圍,下載部分檔案,需指定開始-結束位置 conn.setConnectTimeout(5000); conn.setRequestMethod("GET"); int code = conn.getResponseCode();//200是成功,206也是成功,分割一個檔案返回206 InputStream is = conn.getInputStream(); //由於設定了請求的位置,返回的是當前位置對應的輸入流 RandomAccessFile raf = new RandomAccessFile(newFileName,"rwd"); raf.seek(startIndex); int len = 0 , total = 0; byte[] buffer = new byte[1024]; while((len = is.read(buffer)) != -1){//沒有讀到檔案末尾則繼續寫 raf.write(buffer, 0, len); total += len; RandomAccessFile info = new RandomAccessFile(threadId + ".txt","rwd"); info.write((total + startIndex + "").getBytes());//把下載到最後的位置儲存寫到檔案中 info.close(); } is.close(); raf.close(); //System.out.println("執行緒:"+threadId +"------下載完畢"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ runningThread --; //當執行緒執行完後,表示檔案下載完畢,清除臨時檔案記錄 if(runningThread == 0){ for(int i=1;i <= threadCount; i++){ File file = new File(i+".txt"); if(file.exists()){ file.delete(); } } } } } /** * 讀取txt檔案的內容 * @param file 想要讀取的檔案物件 * @return 返回檔案內容 */ public static String txt2String(File file){ StringBuilder result = new StringBuilder(); try{ BufferedReader br = new BufferedReader(new FileReader(file));//構造一個BufferedReader類來讀取檔案 String s = null; while((s = br.readLine())!=null){//使用readLine方法,一次讀一行 result.append(s); } br.close(); }catch(Exception e){ e.printStackTrace(); } return result.toString(); } } }