多線程斷點下載:顧名思義是用多線程實現的,斷點是當第三方因素(斷電、斷網等)中斷下載時,下次下載可以繼續上次下載的地方下載。
1、通過getContentLength可以獲取要下載文件的大小,這樣可以在本機上創建一個相同大小的文件用來下載。
int fileLength = connection.getContentLength();
2、由於是多線程,所以要給每一個線程均分分配要下載的位置。
for(int i = 0; i < threadCount; i ++) { int startThread = i * blockSize; int endThread = (i + 1) * blockSize - 1; if( i == blockSize - 1) endThread = fileLength -1; new DownloadThread(i, startThread, endThread).start(); }
3、啟動每個線程下載時,請求頭需要Range參數,值是bytes:xxx-xxx某事。比如"Range:0-10100",代表要下載的位置是從0到10100。
connection.setRequestProperty("Range", "bytes:"+startThred+"-" + endThread);
4、然后每次用RandomAccessFile寫入數據到本機文件里。
while((length = inputStream.read(buffer)) != -1) { randomAccessFile.write(buffer, 0, length); }
5、當然每次下載時需要記錄本線程下載了多少,以便斷點時,下載的時候可以從下次下載的地方下載。
total += length; int currentThreadPostion = startThred + total; RandomAccessFile randomAccessFile2 = new RandomAccessFile(file, "rwd"); randomAccessFile2.write(String.valueOf(currentThreadPostion).getBytes()); randomAccessFile2.close();
繼承Thread類的DownloadThread類代碼:

1 public static class DownloadThread extends Thread { 2 private int threadId; 3 private int endThread; 4 private int startThred; 5 public DownloadThread(int threadId, int startThred, int endThread) { 6 this.threadId = threadId; 7 this.startThred = startThred; 8 this.endThread = endThread; 9 } 10 public void run() { 11 //分段請求網絡連接,分段保存在本地 12 synchronized (DownloadThread.class) { 13 currentRunThreadCount += 1; 14 } 15 try { 16 System.err.println("理論線程:"+threadId+",開始位置:"+startThred+",結束位置:"+endThread); 17 URL url = new URL(path); 18 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 19 connection.setRequestMethod("GET"); 20 connection.setConnectTimeout(10 * 1000); 21 File file = new File(threadId+".txt"); 22 if(file.exists()) { //是否斷點 23 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file))); 24 String lastPostion_str = bufferedReader.readLine(); 25 startThred = Integer.parseInt(lastPostion_str); 26 bufferedReader.close(); 27 } 28 //設置分段下載的頭信息 Range:做分段 29 connection.setRequestProperty("Range", "bytes:"+startThred+"-" + endThread); 30 int code = connection.getResponseCode(); 31 System.out.println(code); 32 if(code == 200) { //200:請求全部資源成功 206:代表部分資源請求成功 33 InputStream inputStream = connection.getInputStream(); 34 System.out.println(getFileName(path)); 35 RandomAccessFile randomAccessFile = new RandomAccessFile(new File(getFileName(path)), "rw"); 36 randomAccessFile.seek(startThred); 37 byte[] buffer = new byte[1024*10]; 38 int length = -1; 39 int total = 0;//記錄下載的總量 40 System.err.println("實際線程:"+threadId+",開始位置:"+startThred+",結束位置:"+endThread); 41 while((length = inputStream.read(buffer)) != -1) { 42 randomAccessFile.write(buffer, 0, length); 43 total += length; 44 int currentThreadPostion = startThred + total; 45 RandomAccessFile randomAccessFile2 = new RandomAccessFile(file, "rwd"); 46 randomAccessFile2.write(String.valueOf(currentThreadPostion).getBytes()); 47 randomAccessFile2.close(); 48 } 49 randomAccessFile.close(); 50 inputStream.close(); 51 System.err.println("線程:"+threadId+"下載完畢"); 52 synchronized (DownloadThread.class) { 53 currentRunThreadCount -= 1; 54 if(currentRunThreadCount == 0){ 55 for(int i = 0; i < threadCount; i ++) { 56 File file2 = new File(i+".txt"); 57 file2.delete(); 58 } 59 } 60 } 61 } 62 63 } catch (Exception e) { 64 e.printStackTrace(); 65 } 66 67 68 super.run(); 69 } 70 }
完整代碼:

1 import java.io.BufferedReader; 2 import java.io.File; 3 import java.io.FileInputStream; 4 import java.io.InputStream; 5 import java.io.InputStreamReader; 6 import java.io.RandomAccessFile; 7 import java.net.HttpURLConnection; 8 import java.net.URL; 9 10 11 public class exp6 { 12 13 /** 14 * @param args 15 */ 16 private static int threadCount = 3; 17 private static int blockSize; 18 private static String path = "http://starry97.cn/a.txt"; 19 private static int currentRunThreadCount = 0; 20 public static void main(String[] args) { 21 22 try { 23 URL url = new URL(path); 24 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 25 connection.setRequestMethod("GET"); 26 connection.setConnectTimeout(10 * 1000); 27 int code = connection.getResponseCode(); 28 if(code == 200) { 29 int fileLength = connection.getContentLength(); 30 RandomAccessFile randomAccessFile = new RandomAccessFile(new File(getFileName(path)), "rw"); 31 randomAccessFile.setLength(fileLength); 32 blockSize = fileLength / threadCount; 33 for(int i = 0; i < threadCount; i ++) { 34 int startThread = i * blockSize; 35 int endThread = (i + 1) * blockSize - 1; 36 if( i == blockSize - 1) endThread = fileLength -1; 37 new DownloadThread(i, startThread, endThread).start(); 38 39 } 40 } 41 } catch (Exception e) { 42 e.printStackTrace(); 43 } 44 45 } 46 47 48 public static class DownloadThread extends Thread { 49 private int threadId; 50 private int endThread; 51 private int startThred; 52 public DownloadThread(int threadId, int startThred, int endThread) { 53 this.threadId = threadId; 54 this.startThred = startThred; 55 this.endThread = endThread; 56 } 57 public void run() { 58 synchronized (DownloadThread.class) { 59 currentRunThreadCount += 1; 60 } 61 //分段請求網絡連接,分段保存在本地 62 try { 63 System.err.println("理論線程:"+threadId+",開始位置:"+startThred+",結束位置:"+endThread); 64 URL url = new URL(path); 65 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 66 connection.setRequestMethod("GET"); 67 connection.setConnectTimeout(10 * 1000); 68 File file = new File(threadId+".txt"); 69 if(file.exists()) { //是否斷點 70 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file))); 71 String lastPostion_str = bufferedReader.readLine(); 72 startThred = Integer.parseInt(lastPostion_str); 73 bufferedReader.close(); 74 } 75 //設置分段下載的頭信息 Range:做分段 76 connection.setRequestProperty("Range", "bytes:"+startThred+"-" + endThread); 77 int code = connection.getResponseCode(); 78 System.out.println(code); 79 if(code == 200) { //200:請求全部資源成功 206:代表部分資源請求成功 80 InputStream inputStream = connection.getInputStream(); 81 System.out.println(getFileName(path)); 82 RandomAccessFile randomAccessFile = new RandomAccessFile(new File(getFileName(path)), "rw"); 83 randomAccessFile.seek(startThred); 84 byte[] buffer = new byte[1024*10]; 85 int length = -1; 86 int total = 0;//記錄下載的總量 87 System.err.println("實際線程:"+threadId+",開始位置:"+startThred+",結束位置:"+endThread); 88 while((length = inputStream.read(buffer)) != -1) { 89 randomAccessFile.write(buffer, 0, length); 90 total += length; 91 int currentThreadPostion = startThred + total; 92 RandomAccessFile randomAccessFile2 = new RandomAccessFile(file, "rwd"); 93 randomAccessFile2.write(String.valueOf(currentThreadPostion).getBytes()); 94 randomAccessFile2.close(); 95 } 96 randomAccessFile.close(); 97 inputStream.close(); 98 System.err.println("線程:"+threadId+"下載完畢"); 99 synchronized (DownloadThread.class) { 100 currentRunThreadCount -= 1; 101 if(currentRunThreadCount == 0){ 102 for(int i = 0; i < threadCount; i ++) { 103 File file2 = new File(i+".txt"); 104 file2.delete(); 105 } 106 } 107 } 108 } 109 110 } catch (Exception e) { 111 e.printStackTrace(); 112 } 113 114 115 super.run(); 116 } 117 } 118 119 public static String getFileName(String path) { 120 return path.substring(path.lastIndexOf("/")+1); 121 } 122 123 }