一:需求分析
1:下载远程资源文件,通过多线程下载,达到高效的目的。
2:使用5个线程分别下载文件的不同部分。
二:定义成员变量以及初始化变量
1 // 定义成员变量 2 private String path; // 远程资源路径 3 private String targetPath; // 本地存储路径 4 private DownFileThread[] threads; // 线程list 5 private int threadNum; // 线程数量 6 private long length; // 下载的文件大小 7 8 // 构造初始化 9 public DownloadUtil(String path, String targetPath, int threadNum) { 10 super(); 11 this.path = path; 12 this.targetPath = targetPath; 13 this.threads = new DownFileThread[threadNum]; 14 this.threadNum = threadNum; 15 }
三:多线程下载文件
1 // 多线程下载文件资源 2 public void download() { 3 URL url; 4 try { 5 url = new URL(path); 6 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 7 conn.setReadTimeout(5 * 1000); // 设置超时时间为5秒 8 conn.setRequestMethod("GET"); 9 conn.setRequestProperty("connection", "keep-alive"); 10 conn.setRequestProperty("accept", "*/*"); 11 12 // 获取远程文件的大小 13 length = conn.getContentLength(); 14 conn.disconnect(); 15 16 // 设置本地文件大小 17 RandomAccessFile targetFile = new RandomAccessFile(targetPath, "rw"); 18 targetFile.setLength(length); 19 20 // 每个线程下载大小 21 long avgPart = length / threadNum + 1; 22 // 下载文件 23 for (int i = 0; i < threadNum; i++) { 24 long startPos = avgPart * i; 25 RandomAccessFile targetTmp = new RandomAccessFile(targetPath, 26 "rw"); 27 targetTmp.seek(startPos); // 分段下载 28 threads[i] = new DownFileThread(startPos, targetTmp, avgPart); 29 threads[i].start(); 30 } 31 } catch (Exception e) { 32 e.printStackTrace(); 33 } 34 }
启动多个线程,每个线程下载文件的一部分,并发执行。
四:监控文件下载进度
1 // 监控下载进度 2 public double getDownRate() { 3 int currentSize = 0; 4 for (int i = 0; i < threadNum; i++) { 5 currentSize += threads[i].length; 6 } 7 return currentSize * 1.0 / length; 8 }
如果下载的文件比较大,可以使用进度条显示。
五:定义线程类
1 // 定义线程类 2 class DownFileThread extends Thread { 3 private long startPos; 4 private RandomAccessFile raf; 5 private long size; 6 private long length; 7 8 public DownFileThread(long startPos, RandomAccessFile raf, long size) { 9 super(); 10 this.startPos = startPos; 11 this.raf = raf; 12 this.size = size; 13 } 14 15 public void run() { 16 URL url; 17 try { 18 url = new URL(path); 19 HttpURLConnection conn = (HttpURLConnection) url 20 .openConnection(); 21 conn.setReadTimeout(5 * 1000); // 设置超时时间为5秒 22 conn.setRequestMethod("GET"); 23 conn.setRequestProperty("connection", "keep-alive"); 24 conn.setRequestProperty("accept", "*/*"); 25 26 InputStream in = conn.getInputStream(); 27 in.skip(this.startPos); 28 byte[] buf = new byte[1024]; 29 int hasRead = 0; 30 while (length < size && (hasRead = in.read(buf)) != -1) { 31 raf.write(buf, 0, hasRead); 32 length += hasRead; 33 } 34 raf.close(); 35 in.close(); 36 } catch (Exception e) { 37 e.printStackTrace(); 38 } 39 } 40 }
六:测试多线程下载文件
1 public static void main(String[] args) { 2 String path = "http://localhost:8080/healthcare/html/HealthCare.war"; 3 String targetPath = "D:/healthcare.war"; 4 final DownloadUtil download = new DownloadUtil(path, targetPath, 4); 5 download.download(); 6 // 主线程负责下载文件,在启动一个线程负责监控下载的进度 7 new Thread(new Runnable() { 8 9 @Override 10 public void run() { 11 while (download.getDownRate() < 1) { 12 System.out.println(download.getDownRate()); 13 try { 14 Thread.sleep(200); // 200毫秒扫描一次 15 } catch (InterruptedException e) { 16 e.printStackTrace(); 17 } 18 } 19 } 20 21 }).start(); 22 }
七:全部代码如下
1 /** 2 * 3 */ 4 package com.hlcui.thread; 5 6 import java.io.InputStream; 7 import java.io.RandomAccessFile; 8 import java.net.HttpURLConnection; 9 import java.net.URL; 10 11 /** 12 * @author Administrator 多线程下载文件 13 */ 14 public class DownloadUtil { 15 // 定义成员变量 16 private String path; // 远程资源路径 17 private String targetPath; // 本地存储路径 18 private DownFileThread[] threads; // 线程list 19 private int threadNum; // 线程数量 20 private long length; // 下载的文件大小 21 22 // 构造初始化 23 public DownloadUtil(String path, String targetPath, int threadNum) { 24 super(); 25 this.path = path; 26 this.targetPath = targetPath; 27 this.threads = new DownFileThread[threadNum]; 28 this.threadNum = threadNum; 29 } 30 31 // 多线程下载文件资源 32 public void download() { 33 URL url; 34 try { 35 url = new URL(path); 36 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 37 conn.setReadTimeout(5 * 1000); // 设置超时时间为5秒 38 conn.setRequestMethod("GET"); 39 conn.setRequestProperty("connection", "keep-alive"); 40 conn.setRequestProperty("accept", "*/*"); 41 42 // 获取远程文件的大小 43 length = conn.getContentLength(); 44 conn.disconnect(); 45 46 // 设置本地文件大小 47 RandomAccessFile targetFile = new RandomAccessFile(targetPath, "rw"); 48 targetFile.setLength(length); 49 50 // 每个线程下载大小 51 long avgPart = length / threadNum + 1; 52 // 下载文件 53 for (int i = 0; i < threadNum; i++) { 54 long startPos = avgPart * i; 55 RandomAccessFile targetTmp = new RandomAccessFile(targetPath, 56 "rw"); 57 targetTmp.seek(startPos); // 分段下载 58 threads[i] = new DownFileThread(startPos, targetTmp, avgPart); 59 threads[i].start(); 60 } 61 } catch (Exception e) { 62 e.printStackTrace(); 63 } 64 } 65 66 // 监控下载进度 67 public double getDownRate() { 68 int currentSize = 0; 69 for (int i = 0; i < threadNum; i++) { 70 currentSize += threads[i].length; 71 } 72 return currentSize * 1.0 / length; 73 } 74 75 // 定义线程类 76 class DownFileThread extends Thread { 77 private long startPos; 78 private RandomAccessFile raf; 79 private long size; 80 private long length; 81 82 public DownFileThread(long startPos, RandomAccessFile raf, long size) { 83 super(); 84 this.startPos = startPos; 85 this.raf = raf; 86 this.size = size; 87 } 88 89 public void run() { 90 URL url; 91 try { 92 url = new URL(path); 93 HttpURLConnection conn = (HttpURLConnection) url 94 .openConnection(); 95 conn.setReadTimeout(5 * 1000); // 设置超时时间为5秒 96 conn.setRequestMethod("GET"); 97 conn.setRequestProperty("connection", "keep-alive"); 98 conn.setRequestProperty("accept", "*/*"); 99 100 InputStream in = conn.getInputStream(); 101 in.skip(this.startPos); 102 byte[] buf = new byte[1024]; 103 int hasRead = 0; 104 while (length < size && (hasRead = in.read(buf)) != -1) { 105 raf.write(buf, 0, hasRead); 106 length += hasRead; 107 } 108 raf.close(); 109 in.close(); 110 } catch (Exception e) { 111 e.printStackTrace(); 112 } 113 } 114 } 115 116 // 测试 117 public static void main(String[] args) { 118 String path = "http://localhost:8080/healthcare/html/HealthCare.war"; 119 String targetPath = "D:/healthcare.war"; 120 final DownloadUtil download = new DownloadUtil(path, targetPath, 4); 121 download.download(); 122 // 主线程负责下载文件,在启动一个线程负责监控下载的进度 123 new Thread(new Runnable() { 124 125 @Override 126 public void run() { 127 while (download.getDownRate() < 1) { 128 System.out.println(download.getDownRate()); 129 try { 130 Thread.sleep(200); // 200毫秒扫描一次 131 } catch (InterruptedException e) { 132 e.printStackTrace(); 133 } 134 } 135 } 136 137 }).start(); 138 } 139 }