Java多線程斷點下載

歡迎訪問我的博客:www.yyxxk.comjava

多線程下載已經提升了下載的效率,可是當一些特殊狀況發生的時候,咱們須要對程序進行處理,這樣效率會更高。好比,斷電斷網等形成下載中斷,那麼咱們下一次又要從新開始下載,這樣效率底下,因此咱們能夠考慮使用斷點下載。其原理主要是把每次每一個線程的下載情況(已經下載的位置)保存到文件,下次讀取出來,從上一次下載的位置繼續下載,這樣就大大提升了下載的效率。sql

效果:服務器

開始下載:多線程

下載過程當中:dom

下載過程當中,系統臨時文件保存已下載的位置:ide

下載完畢,系統清楚記錄下載位置的臨時文件:this

附代碼以下:url

  1 import java.io.File;
  2 import java.io.FileInputStream;
  3 import java.io.InputStream;
  4 import java.io.RandomAccessFile;
  5 import java.net.HttpURLConnection;
  6 import java.net.URL;
  7 
  8 /**
  9  * 多線程斷點下載示例
 10  * @author YUANYUAN
 11  *
 12  */
 13 public class Demo {
 14     //下載所使用的線程數
 15     private static int threadCount=3;
 16     //當前活動的線程數
 17     private static int activeThread;
 18 
 19     public static void main(String[] args) throws Exception{
 20         //請求服務器的路徑
 21         String path="http://192.168.2.114:8080/sqlite.exe";
 22         //構造URL地址
 23         URL url=new URL(path);
 24         //打開鏈接
 25         HttpURLConnection conn=(HttpURLConnection) url.openConnection();
 26         //設置請求超時的時間
 27         conn.setConnectTimeout(5000);
 28         //設置請求方式
 29         conn.setRequestMethod("GET");
 30         //獲取相應碼
 31         int code=conn.getResponseCode();
 32         if (code==200) {//請求成功
 33             //獲取請求數據的長度
 34             int length=conn.getContentLength();
 35             //在客戶端建立一個跟服務器文件大小相同的臨時文件
 36             RandomAccessFile raf=new RandomAccessFile("setup.exe", "rwd");
 37             //指定臨時文件的長度
 38             raf.setLength(length);
 39             raf.close();
 40             //假設3個線程去下載資源
 41             //平均每個線程要下載的文件的大小
 42             int blockSize=length/threadCount;
 43             for (int threadId = 1; threadId <= threadCount; threadId++) {
 44                 //當前線程下載數據的開始位置
 45                 int startIndex=blockSize*(threadId-1);
 46                 //當前線程下載數據的結束位置
 47                 int endIndex=blockSize*threadId-1;
 48                 //肯定最後一個線程要下載數據的最大位置
 49                 if (threadId==threadCount) {
 50                     endIndex=length;
 51                 }
 52                 //顯示下載數據的區間
 53                 System.out.println("線程【"+threadId+"】開始下載:"+startIndex+"---->"+endIndex);
 54                 //開啓下載的子線程
 55                 new DownloadThread(path, threadId, startIndex, endIndex).start();
 56                 activeThread++;
 57                 System.out.println("當前活動的線程數:"+activeThread);
 58             }
 59             
 60         }else{//請求失敗
 61             System.out.println("服務器異常,下載失敗!");
 62         }
 63     }
 64     
 65     /**
 66      * 下載文件的子線程 每個文件都下載對應的數據
 67      * @author YUANYUAN
 68      *
 69      */
 70     public static class DownloadThread extends Thread{
 71         private String path;
 72         private int threadId;
 73         private int startIndex;
 74         private int endIndex;
 75         
 76         /**
 77          * 構造方法
 78          * @param path 下載文件的路徑
 79          * @param threadId 下載文件的線程
 80          * @param startIndex 下載文件開始的位置
 81          * @param endIndex 下載文件結束的位置
 82          */
 83         public DownloadThread(String path, int threadId, int startIndex,
 84                 int endIndex) {
 85             this.path = path;
 86             this.threadId = threadId;
 87             this.startIndex = startIndex;
 88             this.endIndex = endIndex;
 89         }
 90 
 91 
 92 
 93         @Override
 94         public void run() {
 95             //構造URL地址
 96             try {
 97                 
 98                 File tempFile=new File(threadId+".txt");
 99                 //檢查記錄是否存在,若是存在讀取數據
100                 if (tempFile.exists()) {
101                     FileInputStream fis=new FileInputStream(tempFile);
102                     byte[] temp=new byte[1024];
103                     int length=fis.read(temp);
104                     //讀取到已經下載的位置
105                     int downloadNewIndex=Integer.parseInt(new String(temp, 0, length));
106                     //設置從新開始下載的開始位置
107                     startIndex=downloadNewIndex;
108                     fis.close();
109                     //顯示真實下載數據的區間
110                     System.out.println("線程【"+threadId+"】真實開始下載數據區間:"+startIndex+"---->"+endIndex);
111                 }
112                 
113                 URL url = new URL(path);
114                 HttpURLConnection conn=(HttpURLConnection) url.openConnection();
115                 conn.setConnectTimeout(5000);
116                 conn.setRequestMethod("GET");
117                 //設置請求屬性,請求部分資源
118                 conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);
119                 int code=conn.getResponseCode();
120                 if (code==206) {//下載部分資源,正常返回的狀態碼爲206
121                     InputStream is=conn.getInputStream();//已經設置了請求的位置,因此返回的是對應的部分資源
122                     //構建隨機訪問文件
123                     RandomAccessFile raf=new RandomAccessFile("setup.exe", "rwd");
124                     //設置 每個線程隨機寫文件開始的位置
125                     raf.seek(startIndex);
126                     //開始寫文件
127                     int len=0;
128                     byte[] buffer=new byte[1024];
129                     //該線程已經下載數據的長度
130                     int total=0;
131                     
132                     while((len=is.read(buffer))!=-1){//讀取輸入流
133                         //記錄當前線程已下載數據的長度
134                         RandomAccessFile file=new RandomAccessFile(threadId+".txt","rwd");
135                         raf.write(buffer,0,len);//寫文件
136                         total+=len;//更新該線程已下載數據的總長度
137                         System.out.println("線程【"+threadId+"】已下載數據:"+(total+startIndex));
138                         //將已下載數據的位置記錄寫入到文件
139                         file.write((startIndex+total+"").getBytes());
140                         file.close();
141                     }
142                     is.close();
143                     raf.close();
144                     //提示下載完畢
145                     System.out.println("線程【"+threadId+"】下載完畢");
146                 }
147             } catch (Exception e) {
148                 e.printStackTrace();
149                 System.out.println("線程【"+threadId+"】下載出現異常!!");
150             }finally{
151                 //活動的線程數減小
152                 activeThread--;
153                 if (activeThread==0) {
154                     for (int i = 1; i <= threadCount; i++) {
155                         File tempFile=new File(i+".txt");
156                         tempFile.delete();
157                     }
158                     System.out.println("下載完畢,已清除所有臨時文件");
159                 }
160             }
161             
162         }
163     }
164 }
相關文章
相關標籤/搜索