Java多執行緒斷點續傳下載
阿新 • • 發佈:2019-01-26
package com.example.threadpool; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; /** * Created by on 2017/11/23. */ public class DownloadTest2 { private static String path = "http://120.27.23.105/version/baidu.apk"; private static int threadCount = 20; private static int activeThread; public static void main(String[] arg0){ try { //構造請求路徑 URL url = new URL(path); //開啟連線地址 HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); //設定請求時間 httpURLConnection.setConnectTimeout(5000); //設定請求方式 httpURLConnection.setRequestMethod("GET"); //獲取請求碼 int code = httpURLConnection.getResponseCode(); if(code == 200){ //請求成功 //獲取請求資料的長度 int contentLength = httpURLConnection.getContentLength(); //在客戶端建立一個大小相同的臨時檔案 RandomAccessFile randomAccessFile = new RandomAccessFile("baidu.apk","rwd"); //指定臨時檔案的長度(和下載長度相同) randomAccessFile.setLength(contentLength); //關閉流 randomAccessFile.close(); //求出誒條線城需要下載的長度 int blockSize = contentLength / threadCount; //迴圈開啟執行緒 for (int i = 1; i < threadCount; i++) { //計算當前執行緒下載的開始位置 int startIndex = blockSize * (i - 1); //計算當前執行緒下載的結束位置 int endIndex = blockSize * i - 1; //確定是最後一個執行緒(最後一個執行緒需要特殊處理) if(i == threadCount){ //i == threadCount說明是最後一個執行緒 //為最後一個執行緒賦值最大長度 endIndex = contentLength; } //顯示下載資料的區間 System.out.println("執行緒【" + i + "】開始下載:" + startIndex + "---->" + endIndex); //開啟執行緒進行下載 new DownloadThread(path,i,startIndex,endIndex).start(); activeThread ++; System.out.println("當前活動的執行緒數:" + activeThread); } }else{ System.out.println("伺服器異常,下載失敗!"); } } catch (Exception e) { e.printStackTrace(); } } //內部類分配執行緒 public static class DownloadThread extends Thread{ //路徑 private String path; private int threadId; private int startIndex; private int endIndex; //有參構造 public DownloadThread(String path, int threadId, int startIndex, int endIndex) { this.path = path; this.threadId = threadId; this.startIndex = startIndex; this.endIndex = endIndex; } @Override public void run() { try { //構造URL地址 File file = new File(threadId+".txt"); //檢查記錄是否存在,如果存在讀取資料 if(file.exists()){ //檔案流 FileInputStream fileInputStream = new FileInputStream(file); //讀取長度 byte[] temp = new byte[1024]; int read = fileInputStream.read(temp); //讀取到已經下載的位置 int downloadNewindex = Integer.parseInt(new String(temp, 0, read)); //重新設定開始下載的開始位置 startIndex = downloadNewindex; fileInputStream.close(); //顯示真實下載資料的區間 System.out.println("執行緒【" + threadId + "】真實開始下載資料區間:" + startIndex + "---->" + endIndex); } //設定讀取 URL url = new URL(path); //資料請求 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); //設定讀取時間 connection.setConnectTimeout(5000); //設定讀取方式 connection.setRequestMethod("GET"); //設定請求頭,請求屬性和請求資源部分 connection.setRequestProperty("Range","bytes="+startIndex+"-"+endIndex); //請求碼 int code = connection.getResponseCode(); //因為加了請求頭,請求成功返回206 if(code == 206){ InputStream inputStream = connection.getInputStream(); //構建隨機的訪問檔案 RandomAccessFile randomAccessFile = new RandomAccessFile("baidu.apk","rwd"); //社會組誒一段隨機開始的位置 randomAccessFile.seek(startIndex); //開始寫檔案 int len = 0; byte[] buffer = new byte[1024]; //該執行緒已下載的資料長度 int total = 0; //讀取寫入 while ((len = inputStream.read(buffer)) != -1){ //記錄當前執行緒已下載資料的長度 RandomAccessFile accessFile = new RandomAccessFile(threadId+".txt","rwd"); accessFile.write(buffer,0,len); //更新執行緒已下載的長度 total += len; System.out.println("執行緒【" + threadId + "】已下載資料:" + (total + startIndex)); //將已下載資料的位置記錄寫入到檔案 accessFile.write((startIndex+total+"").getBytes()); accessFile.close(); } inputStream.close(); randomAccessFile.close(); //提示下載完畢 System.out.println("執行緒【" + threadId + "】下載完畢"); } } catch (Exception e) { e.printStackTrace(); System.out.println("執行緒【" + threadId + "】下載出現異常!!"); }finally { //關閉執行緒 activeThread--; if(activeThread == 0){ for (int i = 0; i < threadCount; i++) { File file = new File(i+".txt"); //清理檔案 file.delete(); } System.out.println("下載完畢,已清除全部臨時檔案"); } } } } }