歡迎訪問我的博客: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 }