废话不多说,直接上代码
1 import java.io.File; 2 import java.io.InputStream; 3 import java.io.RandomAccessFile; 4 import java.net.HttpURLConnection; 5 import java.net.URL; 6 7 public class DownUtil { 8 //定义下载资源的路径 9 private String path; 10 //指定所下载的文件的保存位置 11 private String targetFile; 12 //定义需要使用多少个线程下载资源 13 private int threadNum; 14 //定义下载的线程对象 15 private DownThread[] threads; 16 //定义下载的文件的总大小 17 private int fileSize; 18 19 //构造器 20 public DownUtil(String path, String targetFile, int threadNum) { 21 this.path = path; 22 this.threadNum = threadNum; 23 //初始化threads数组 24 threads = new DownThread[threadNum]; 25 this.targetFile = targetFile; 26 } 27 28 public void download() throws Exception { 29 URL url = new URL(path); 30 //1.通过调用URL对象的openConnection()方法来创建URLConnection对象 31 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 32 //2.设置URLConnection的参数和普通请求属性 33 conn.setConnectTimeout(5 * 1000); 34 conn.setRequestMethod("GET"); 35 36 //得到文件大小 37 fileSize = conn.getContentLength(); 38 conn.disconnect(); 39 int currentPartSize = fileSize / threadNum + 1;//每个线程所要处理任务大小 40 File tarFile = new File(targetFile.substring(0, targetFile.lastIndexOf("/"))); 41 if (!tarFile.exists()) { 42 tarFile.mkdirs(); 43 } 44 RandomAccessFile file = new RandomAccessFile(targetFile, "rw"); 45 //设置本地文件的大小 46 file.setLength(fileSize); 47 file.close(); 48 for (int i = 0; i < threadNum; i++) { 49 //计算每个线程下载开始的位置 50 int startPos = i * currentPartSize; 51 //每个线程使用一个RandomAccessFile进行下载 52 RandomAccessFile currentPart = new RandomAccessFile(targetFile, "rw"); 53 //定位该线程的下载位置 54 currentPart.seek(startPos); 55 //创建下载线程 56 threads[i] = new DownThread(startPos, currentPartSize, currentPart); 57 //启动下载线程 58 threads[i].start(); 59 } 60 } 61 62 //获取下载的完成百分比 63 public double getCompleteRate() { 64 //统计多个线程已经下载的总大小 65 int sumSize = 0; 66 for (int i = 0; i < threadNum; i++) { 67 sumSize += threads[i].length; 68 } 69 //返回已经完成的百分比 70 return sumSize * 1.0 / fileSize; 71 } 72 73 public class DownThread extends Thread { 74 //当前线程的下载位置 75 private int startPos; 76 //定义当前线程负责下载的文件大小 77 private int currentPartSize; 78 //当前线程需要下载的文件块 79 private RandomAccessFile currentPart; 80 //定义该线程已下载的字节数 81 public int length; 82 83 //构造器 84 public DownThread(int startPos, int currentPartSize, RandomAccessFile currentPart) { 85 this.startPos = startPos; 86 this.currentPartSize = currentPartSize; 87 this.currentPart = currentPart; 88 } 89 90 //下载线程的主函数体 91 public void run() { 92 try { 93 URL url = new URL(path); 94 //1.通过调用URL对象的openConnection()方法来创建URLConnection对象 95 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 96 //2.设置URLConnection的参数和普通请求属性 97 conn.setConnectTimeout(5 * 1000); 98 conn.setRequestMethod("GET"); 99 //4.远程资源变为可用,程序可以通过输入流读取远程资源的数据 100 InputStream inStream = conn.getInputStream(); 101 102 //跳过stratPos个字节,表明该线程只下载自己负责的那部分文件 103 //同时每个线程都会在指定的文件区域写入,所以不会因为多线程而出 104 //现资源组合的错乱,从指定位置读取资源,写入到指定位置 105 inStream.skip(this.startPos); 106 byte[] buffer = new byte[1024];//自己设置一个缓冲区 107 int hasread; 108 109 //-----------------读取网路数据,并写入本地文件------------------- 110 //inStream.read(buffer))==-1 表示读取到文件末尾 111 while (length < currentPartSize && (hasread = inStream.read(buffer)) != -1) { 112 currentPart.write(buffer, 0, hasread); 113 //累计该线程下载的总大小 114 length += hasread; 115 //System.out.println(getName()+" "+hasread); 116 } 117 //System.out.println(getName()+" length "+length+" currentPartSize "+currentPartSize); 118 //即使length>currentPartSize会是的该线程多写入几个字节, 119 //但是下一个线程会从文件的指定位置写入,就会覆盖掉之前线程多写的一部分内容 120 currentPart.close(); 121 inStream.close(); 122 } catch (Exception e) { 123 e.printStackTrace(); 124 } 125 } 126 127 } 128 }
调用上述下载工具类
1 public static String jarurl = "http://softdown1.hao123.com/hao123-soft-online-bcs/soft/2017_09_29_jpwb2017qj.exe"; // 下载地址 2 private Thread processThread = new Thread(); 3 public static boolean downloaded = false;//下载完成与否 4 public static boolean errored = false;//下载出错与否 5 public void dowload() { 6 try { 7 if (HttpUtil.isConnect(jarurl)) { 8 //初始化DownUtil对象 9 //配置4个线程去下载数据 10 //第二个参数文件名可随意更改,下载到本地项目中 11 final DownUtil downUtil = new DownUtil(jarurl,"rct-demo.exe", 4); 12 //开始下载 13 downUtil.download(); 14 //启动线程获取下载进度 15 processThread = new Thread(() -> 16 { 17 while (downUtil.getCompleteRate() < 1) { 18 //每隔0.1秒查询一次任务的完成进度 19 log.info("已完成:{}", downUtil.getCompleteRate()); 20 try { 21 Thread.sleep(100); 22 } catch (Exception ex) { 23 } 24 } 25 log.info("已完成:{}", downUtil.getCompleteRate() >= 1 ? "1.0" : downUtil.getCompleteRate()); 26 if (downUtil.getCompleteRate() >= 1) { 27 //下载完成的一些操作 28 } 29 }); 30 processThread.start(); 31 } 32 } catch (Exception e) { 33 downloaded = false; 34 errored = true; 35 e.printStackTrace(); 36 } 37 }
判定连接是否可用
1 private static URL url; 2 private static HttpURLConnection con; 3 private static int state = -1; 4 /** 5 * 检测当前URL是否可连接或是否有效, 6 * 7 * @param urlStr 指定URL网络地址 8 * @return URL 9 */ 10 public synchronized static boolean isConnect(String urlStr) { 11 if (urlStr == null || urlStr.length() <= 0) { 12 return false; 13 } 14 try { 15 url = new URL(urlStr); 16 con = (HttpURLConnection) url.openConnection(); 17 state = con.getResponseCode(); 18 if (state == 200) { 19 log.info("{}地址可用!", urlStr); 20 return true; 21 } 22 } catch (Exception ex) { 23 log.info("{}地址不可用", urlStr); 24 } 25 return false; 26 }