1. 程式人生 > >Java實現多線程下載、斷點續傳

Java實現多線程下載、斷點續傳

get import 服務 結束 parseint RR range turn con

開三個線程下載,代碼:

package demo;

import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

public class MutilDownLoad {

    // 放在Tomcat下的一個文件
    static String path = "http://192.168.87.1:8080/lol.exe";

    // 多線程的個數(開3個線程)
    private static final int
THREADACOUNT = 3; public static void main(String[] args) { try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); int code = conn.getResponseCode();
if (code == 200) { // 獲取文件大小 int length = conn.getContentLength(); // 創建一個和服務器獲取的文件大小一致的文件 RandomAccessFile randomAccessFile = new RandomAccessFile("lol.exe", "rw"); randomAccessFile.setLength(length); // 算出每個線程下載大小
int blockSize = length / THREADACOUNT; // 計算每個線程的起始位置和結束位置 for (int i = 0; i < THREADACOUNT; i++) { int startIndex = i * blockSize; int endIndex = (i + 1) * blockSize - 1; // 處理最後一個線程結束位置 if (i == THREADACOUNT - 1) { endIndex = length - 1; } // 開啟多線程下載 new DowdLoadThread(startIndex, endIndex, i).start(); } } } catch (Exception e) { e.printStackTrace(); } } // 定義多線程下載文件 private static class DowdLoadThread extends Thread { private int startIndex; private int endIndex; private int threadID; public DowdLoadThread(int startIndex, int endIndex, int threadID) { this.startIndex = startIndex; this.endIndex = endIndex; this.threadID = threadID; } @Override public void run() { try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); // 設置 conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex); int code = conn.getResponseCode(); // 請求部分資源成功(206) if (code == 206) { // 隨機讀寫文件對象 RandomAccessFile randomAccessFile = new RandomAccessFile("lol.exe", "rw"); randomAccessFile.seek(startIndex); InputStream in = conn.getInputStream(); // 當前線程下載的大小 int len = -1; byte[] buffer = new byte[1024]; while ((len = in.read(buffer)) != -1) { randomAccessFile.write(buffer, 0, len); } randomAccessFile.close(); System.out.println("線程id:" + threadID + "已下載完畢"); } } catch (Exception e) { e.printStackTrace(); } } } }

執行:

技術分享圖片

接下來實現斷點續傳:

package demo;

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 MutilDownLoad {

    // 定義下載的路徑
    private static String path = "http://192.168.87.1:8080/lol.exe";

    // 假設開三個線程
    private static final int threadCount = 3;

    // 代表當前正在運行的線程
    private static int runningThread;

    public static void main(String[] args) {

        try {

            URL url = new URL(path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5000);
            int code = conn.getResponseCode();
            if (code == 200) {

                int length = conn.getContentLength();

                runningThread = threadCount;

                System.out.println("length:" + length);

                RandomAccessFile rafAccessFile = new RandomAccessFile(getFilename(path), "rw");
                rafAccessFile.setLength(length);

                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 {
                URL url = new URL(path);

                HttpURLConnection conn = (HttpURLConnection) url.openConnection();

                conn.setRequestMethod("GET");

                conn.setConnectTimeout(5000);

                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);

                    startIndex = lastPosition + 1;

                    System.out.println("線程id::" + threadId + "真實下載的位置" + ":" + startIndex + "-----" + endIndex);

                    fis.close();
                }

                conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);

                int code = conn.getResponseCode();

                if (code == 206) {

                    RandomAccessFile raf = new RandomAccessFile(getFilename(path), "rw");

                    raf.seek(startIndex);

                    InputStream in = conn.getInputStream();

                    int len = -1;
                    byte[] buffer = new byte[1024 * 1024];// 1Mb

                    int total = 0;

                    while ((len = in.read(buffer)) != -1) {
                        raf.write(buffer, 0, len);

                        total += len;
                        // 實現斷點續傳 就是把當前線程下載的位置 給存起來 下次再下載的時候 就是按照上次下載的位置繼續下載
                        // 存到一個普通的.txt文本中
                        int currentThreadPosition = startIndex + total;

                        RandomAccessFile raff = new RandomAccessFile(getFilename(path) + threadId + ".txt", "rwd");
                        raff.write(String.valueOf(currentThreadPosition).getBytes());
                        raff.close();

                    }
                    raf.close();

                    System.out.println("線程id:" + threadId + "---下載完畢了");

                    // 把.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();
            }

        }
    }

    // 獲取文件的名字
    public static String getFilename(String path) {

        int start = path.lastIndexOf("/") + 1;
        return path.substring(start);
    }

}

技術分享圖片

Java實現多線程下載、斷點續傳