基本原理:利用HttpsURLConnection獲取要下載文件的長度、頭部等相關信息,并設置響應的頭部信息。并且通過HttpsURLConnection獲取輸入流,將文件分成指定的塊,每一塊單獨開辟一個線程完成數據的讀取、寫入。通過輸入流讀取下載文件的信息,然后將讀取的信息用RandomAccessFile隨機寫入到本地文件中。同時,每個線程寫入的數據都文件指針也就是寫入數據的長度,需要保存在一個臨時文件中。這樣當本次下載沒有完成的時候,下次下載的時候就從這個文件中讀取上一次下載的文件長度,然后繼續接著上一次的位置開始下載。并且將本次下載的長度寫入到這個文件中。

 1 package com.gaolei.download;
 2 
 3 import java.io.File;
 4 import java.io.IOException;
 5 import java.io.InputStream;
 6 import java.io.RandomAccessFile;
 7 import java.net.URL;
 8 
 9 import javax.net.ssl.HttpsURLConnection;
10 
11 public class MulThreadDownload {
12 
13     public static void main(String[] args) throws Exception {
14         String path = "http://192.168.0.1/videonews/QQWubiSetup.exe";
15         new MulThreadDownload().download(path, 3);
16     }
17 
18     /**
19      * 下載文件
20      *
21      * @param path網絡文件路徑
22      * @throws Exception
23      */
24     private void download(String path, int threadsize) throws Exception {
25         URL url = new URL(path);
26         HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
27         conn.setConnectTimeout(5000);
28         conn.setRequestMethod("GET");
29         if (conn.getResponseCode() == 200) {
30             int length = conn.getContentLength(); // 獲取網絡文件的長度
31             File file = new File(getFilename(path));
32             RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");// 在本地生成一個長度相等的文件
33             accessFile.setLength(length);
34             accessFile.close();
35 
36             // 計算每條線程負責下載的數據量
37             int block = length % threadsize == 0 ? length / threadsize : length
38                     / threadsize + 1;
39             for (int threadid = 0; threadid < threadsize; threadid++) {
40                 new DownloadThread(threadid, block, url, file).start();
41             }
42         } else {
43             System.out.println("下載失敗!");
44         }
45 
46     }
47 
48     private class DownloadThread extends Thread {
49 
50         private int threadid;
51         private int block;
52         private URL url;
53         private File file;
54 
55         public DownloadThread(int threadid, int block, URL url, File file) {
56             this.threadid = threadid;
57             this.block = block;
58             this.url = url;
59             this.file = file;
60         }
61 
62         @Override
63         public void run() {
64             int start = threadid * block; // 計算該線程從網絡文件的什么位置開始下載
65             int end = (threadid + 1* block - 1// 下載到網絡文件的什么位置結束
66 
67             try {
68                 RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");// 在本地生成一個長度相等的文件
69                 accessFile.seek(start);
70                 HttpsURLConnection conn = (HttpsURLConnection) url
71                         .openConnection();
72                 conn.setConnectTimeout(5000);
73                 conn.setRequestMethod("GET");
74                 conn.setRequestProperty("Range""bytes=" + start + "-" + end);
75                 if (conn.getResponseCode() == 206) {
76                     InputStream inStream = conn.getInputStream();
77                     byte[] buffer = new byte[1024];
78                     int len = 0;
79                     while ((len = inStream.read(buffer)) != -1) {
80                         accessFile.write(buffer, 0, len);
81                     }
82                     accessFile.close();
83                     inStream.close();
84                 }
85                 System.out.println("" + (threadid + 1+ "條線程已經下載完成!");
86             } catch (IOException e) {
87                 e.printStackTrace();
88             }
89 
90         }
91 
92     }
93 
94     private String getFilename(String path) {
95         return path.substring(path.lastIndexOf("/"+ 1);
96     }
97 }
98