1. 程式人生 > >Java多執行緒斷點續傳下載

Java多執行緒斷點續傳下載

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("下載完畢,已清除全部臨時檔案");
                    }
                }
        }
    }
}