在Java中使用多執行緒結合斷點續傳實現一個簡單的檔案下載器
阿新 • • 發佈:2019-02-18
這篇部落格介紹在android中使用多執行緒和斷點續傳實現一個簡單的檔案下載器
第一步:啟動Tomcat伺服器,將需要下載的檔案部署到Tomcat伺服器上
第二步:使用eclipse建立一個Java工程,並且在工程中新增下面的程式碼
第三步:執行程式,等到Console輸出框中輸出下圖中所示的資訊表示下載完成package com.fyt.multidownload; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; public class MultiDownload { //下載檔案時開啟的執行緒的個數 static int ThreadCount = 3; //結束的執行緒的個數 static int finishedThread = 0; //設定檔案的下載地址 static String path = "http://192.168.0.101:8080/app/genymotion-2.2.0-vbox.exe"; public static void main(String[] args) { try { //將下載地址封裝成Url物件 URL url = new URL(path); //建立連線物件,此時未建立連線 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); //設定請求方式為get請求 conn.setRequestMethod("GET"); //設定連線超時 conn.setConnectTimeout(5000); //設定讀取超時 conn.setReadTimeout(5000); //如果請求傳送成功 if(conn.getResponseCode() == 200) { //獲得需要下載的檔案的長度 int length = conn.getContentLength(); //建立File物件 File file = new File("genymotion-2.2.0-vbox.exe"); //生成臨時檔案(臨時檔案的大小為下載的檔案的大小) RandomAccessFile raf = new RandomAccessFile(file, "rwd"); //設定臨時檔案的大小 raf.setLength(length); //關閉臨時檔案 raf.close(); //計算出每個執行緒應該下載多少位元組 int size = length / ThreadCount; //遍歷建立好的執行緒 for (int i = 0; i < ThreadCount; i++) { //計算執行緒下載的開始位置 int startIndex = i * size; //計算執行緒下載的結束位置 int endIndex = (i + 1) * size - 1; //如果是最後一個執行緒,那麼結束位置寫死 if(i == ThreadCount - 1) { endIndex = length - 1; } //System.out.println("執行緒" + i + "的下載區間是:" + startIndex + "---" + endIndex); //建立下載執行緒 //第一個引數:下載開始的位置 //第二個引數:下載結束的位置 //第三個引數:執行緒的Id DownLoadThread thread = new DownLoadThread(startIndex, endIndex, i); //啟動下載執行緒 thread.start(); } } } catch (Exception e) { e.printStackTrace(); } } } //建立一個繼承自執行緒類的下載執行緒類 class DownLoadThread extends Thread { //執行緒下載的開始位置 int startIndex; //執行緒下載的結束位置 int endIndex; //執行緒的Id int threadId; //下載執行緒的構造方法 public DownLoadThread(int startIndex, int endIndex, int threadId) { super(); //設定執行緒下載的開始位置 this.startIndex = startIndex; //設定執行緒下載的結束位置 this.endIndex = endIndex; //設定執行緒的Id this.threadId = threadId; } //執行執行緒 @Override public void run() { try { //建立儲存下載進度的臨時檔案 File progressFile = new File(threadId + ".txt"); //如果進度臨時檔案存在 if(progressFile.exists()) { //建立檔案輸入流 FileInputStream fis = new FileInputStream(progressFile); //InputStreamReader:建立檔案的輸入流緩衝區物件 //BufferedReader:建立檔案的讀取緩衝區物件 BufferedReader br = new BufferedReader(new InputStreamReader(fis)); //從進度臨時檔案中讀取出上一次下載的總進度 //然後與原本的開始位置相加,得到新的開始位置 startIndex += Integer.parseInt(br.readLine()); //關閉檔案輸入流 fis.close(); } //System.out.println("執行緒" + threadId + "的下載區間是:" + startIndex + "---" + endIndex); //使用URL物件封裝下載檔案的地址 URL url = new URL(MultiDownload.path); //建立連線物件,此時未建立連線 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); //設定請求方式為get請求 conn.setRequestMethod("GET"); //設定連線超時 conn.setConnectTimeout(5000); //設定讀取超時 conn.setReadTimeout(5000); //設定本次http請求所請求的資料的區間 conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex); //請求部分資料 //請求部分資料請求成功的響應碼是206 if(conn.getResponseCode() == 206) { //流裡此時只有1/3原檔案的資料 //從響應中獲取檔案輸入流 InputStream is = conn.getInputStream(); byte[] b = new byte[1024]; int len = 0; int total = 0; //拿到臨時檔案的輸出流 File file = new File("genymotion-2.2.0-vbox.exe"); //建立一個臨時檔案 RandomAccessFile raf = new RandomAccessFile(file, "rwd"); //把檔案的寫入位置移動至startIndex raf.seek(startIndex); while((len = is.read(b)) != -1) { //每次讀取流裡資料之後,同步把資料寫入臨時檔案 raf.write(b, 0, len); total += len; //System.out.println("執行緒" + threadId + "下載了" + total); //生成一個專門用來記錄下載進度的臨時檔案 RandomAccessFile progressRaf = new RandomAccessFile(progressFile, "rwd"); //每次讀取流裡資料之後,同步把當前執行緒下載的總進度寫入進度臨時檔案中 progressRaf.write((total + "").getBytes()); //關閉進度臨時檔案 progressRaf.close(); } System.out.println("執行緒" + threadId + "下載完畢-------------------小志參上!"); //關閉臨時檔案 raf.close(); //完成下載的執行緒的個數增加1 MultiDownload.finishedThread++; //MultiDownload.path表示檔案的下載地址 synchronized (MultiDownload.path) { //如果三個下載執行緒都完成了下載任務 if(MultiDownload.finishedThread == MultiDownload.ThreadCount) { //變數所有的下載執行緒所在的臨時檔案 for (int i = 0; i < MultiDownload.ThreadCount; i++) { //獲得下載執行緒下載的臨時檔案 File f = new File(i + ".txt"); //刪除下載執行緒下載的臨時檔案 f.delete(); } //設定結束下載任務的下載執行緒的個數為0 MultiDownload.finishedThread = 0; } } } } catch (Exception e) { e.printStackTrace(); } } }
此時在Java工程下可以看到多了一個genymotion-2.2.0-vbox.exe,表示下載成功了