多線程下載

package com.zhaoda.zxy.myapplication;

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;

/**
 * Created by ZXY on 2016/5/23.
 */
public class MutilDownload2 {
    //[1]定義h下載路徑
    private static String path = "http://172.17.242.1:8080/as.exe";
    private static final int threadCount = 3;//假設開三個線程
    private static int runningThread;//代表當前正在運行的線程

    public static void main(String[] args) {
//[一☆☆☆☆☆]獲取服務器文件大小,要計算每個線程的下載開始的位置和結束位置
        try {
            //1.創建url對象參數就是網址
            URL url = new URL(path);
            //2.獲取HttpURLConnecton鏈接對象
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            //3.設置參數發送get請求
            conn.setRequestMethod("GET");
            //4.設置鏈接網路的超時時間
            conn.setConnectTimeout(5000);
            //5.獲取服務器返回狀態碼
            int code = conn.getResponseCode();
            if (code == 200) {//200代表獲取服務器資源全部成功,206請求部分資源
                //6.獲取服務器文件的大小
                int length = conn.getContentLength();
                //6.1把線程的數量賦給正在運行的線程
                runningThread = threadCount;
                //[二☆☆☆☆☆]創建大小和服務器一模一樣的文件目的提前把空間申請出來
                RandomAccessFile raf = new RandomAccessFile("temp.exe", "rw");
                raf.setLength(length);
                //7.算出每個線程下載的大小
                int blockSize = length / threadCount;
                //[三☆☆☆☆☆]計算每個線程開始位置和結束位置
                for (int i = 0; i < threadCount; i++) {
                    int startIndex = i * blockSize;//每個線程下載開始位置
                    int endIndex = (i + 1) * blockSize - 1;
                    if (i == threadCount - 1) {
                        //說明是最好一個線程
                        endIndex = length - 1;
                    }
                    System.out.println("線程id:" + i + "理論下載位置" + ":" + startIndex + "----" + endIndex);

                    //[四☆☆☆☆☆]開啓線程去服務器下載文件
                    DownLoadThread downLoadThread = new DownLoadThread(startIndex, endIndex, i);
                    downLoadThread.start();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //定義線程去服務器下載文件
    private static class DownLoadThread extends Thread {
        //通過構造方法把每個線程下載的開始位置和結束位置
        private int startIndex;
        private int endIndex;
        private int threadId;

        public DownLoadThread(int startIndex, int endIndex, int threadId) {

            this.startIndex = startIndex;
            this.endIndex = endIndex;
            this.threadId = threadId;
        }

        @Override
        public void run() {
            //實現去服務器下載文件的邏輯
            try {
                //1.創建url對象參數就是網址
                URL url = new URL(path);
                //2.獲取HttpURLConnecton鏈接對象
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                //3.設置參數發送get請求
                conn.setRequestMethod("GET");
                //4.設置鏈接網路的超時時間
                conn.setConnectTimeout(5000);
                //4.0如果下載中間斷過,繼續上次的位置繼續下載,從文件中讀取上次下載的位置
                File file = new File(getFilename(path) + threadId + ".txt");
                if (file.exists() && file.length() > 0) {
                    FileInputStream fis = new FileInputStream(file);
                    BufferedReader bufr = new BufferedReader(new InputStreamReader(fis));
                    String lastPositionn = bufr.readLine();//讀取出來內容就是上次下載位置
                    int lastPosition = Integer.parseInt(lastPositionn);
                    //4.0.1要改變startIndex位置
                    startIndex = lastPosition;
                    System.out.println("線程id:" + threadId + "真實下載位置" + ":" + startIndex + "----" + endIndex);
                    fis.close();
                }
                //4.1設置一個請求頭Range(作用告訴服務器每個線程下載的開始位置和結束位置)
                conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
                //5.獲取服務器返回狀態碼
                int code = conn.getResponseCode();
                if (code == 206) {//200代表獲取服務器資源全部成功,206請求部分資源
                    //6.創建隨機讀寫文件對象
                    RandomAccessFile raf = new RandomAccessFile(getFilename(path), "rw");
                    //6.1每個線程都從自己位置開始寫
                    raf.seek(startIndex);
                    InputStream in = conn.getInputStream();//獲取服務器文件
                    //7.把數據寫到文件中.
                    int len = -1;
                    byte[] buffer = new byte[1024 * 1024];
                    int total = 0;//當前線程下載的大小
                    while ((len = in.read(buffer)) != -1) {
                        raf.write(buffer, 0, len);
                        total += len;
                        //8.實現斷點續傳就是把當前線程下載的位置存起來,下次再下載就是按照上次下載位置繼續下載就行了
                        int currrentThreadPosition = startIndex + total;//佔時存在txt文本中
                        //q.用來存當前線程下載的位置
                        RandomAccessFile raff = new RandomAccessFile(getFilename(path) + threadId + ".txt", "rwd");
                        raff.write(String.valueOf(currrentThreadPosition).getBytes());
                        raff.close();
                    }
                    raf.close();//關閉流,釋放資源
                    System.out.println("線程id:" + threadId + "下載完畢!");
                    //10.把.txt文件刪除
                    synchronized (DownLoadThread.class) {
                        runningThread--;
                        if (runningThread == 0) {
                            //說明所有線程都執行完畢了,就把.txt文件刪除了
                            for (int i = 0; i < threadCount; i++) {
                                File delteFile = new File(getFilename(path) + i + ".txt");
                                delteFile.delete();

                            }
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    //獲取文件的名字  http://172.17.242.1:8080/as.exe
    public static String getFilename(String path) {
        int start = path.lastIndexOf("/") + 1;
        return path.substring(start);
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章