多线程下载原理
基本原理:利用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 @Override63 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) url71 .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