多线程断点下载:顾名思义是用多线程实现的,断点是当第三方因素(断电、断网等)中断下载时,下次下载可以继续上次下载的地方下载。
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 }