java多线程下载
2016-03-10 14:04
381 查看
package com.hlj.download; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.ProtocolException; import java.net.URL; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; /** * java多线程下载 * 1 获得要下载的文件的大小 * 2 用RandomAccessFile生成一个同等大小的文件,相当于一个容器 * 3 计算每个线程下载的开始位置和结束位置 * 4 用conn.setRequestProperty("Range", "bytes=" + start + "-" + end);获得要下载文件的部分资源 * 5 通过RandomAccessFile 的 seek(start)方法设置该线程对该容器写的位置 * @author wizard * */ public class ThreadLoad { private String path = null; private int threadNum = 1; private boolean pause = false; private String name = null; private MyThread thread[]; private int contentLength = -1; private AtomicInteger count = new AtomicInteger(0);// 判断是否全部线程执行完 public AtomicLong downProgress = new AtomicLong(0);// 判断是否全部线程执行完 public ThreadLoad(String path, String name, int threadNum) { this.path = path; this.name = name; this.threadNum = threadNum; thread = new MyThread[threadNum + 1]; } public ThreadLoad(int threadNum) { this.threadNum = threadNum; thread = new MyThread[threadNum + 1]; } public ThreadLoad() { thread = new MyThread[threadNum + 1]; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getThreadNum() { return threadNum; } public boolean downLoadFile(String path, String name) throws IOException { setPath(path); setName(name); return downLoadFile(); } /** * 判断是否全部结束额 * @return */ public boolean finish(){ return count.get() == threadNum; } /** * 下载 * * @return * @throws IOException */ public boolean downLoadFile() throws IOException { if ("".equals(path) || path == null ) { return false; } int len = getContentLength(); if (len != -1) { setFileSize(name, len);// 创建文件 int blockSize = len / threadNum; long begin = System.currentTimeMillis(); for (int threadId = 1; threadId <= threadNum; threadId++) { int start = (threadId - 1) * blockSize; int endIndex = threadId * blockSize - 1; if (threadId == threadNum) {// 最后一个线程下载的长度要稍微长一点 endIndex = len; } System.out.println("线程:" + threadId + "下载:---" + start + "--->" + endIndex); thread[threadId] = new MyThread(threadId, start, endIndex, name); thread[threadId].start(); } } else { return false; } return true; } /** * 暂停下载 */ public void pauseDown() { pause = true; } /** * 继续下载 */ public void contiuneDown() { pause = false; for (int i = 1; i <= threadNum; i++) { if (thread[i] != null) { synchronized (thread[i]) { thread[i].notify(); } } } } /** * 先设置一个空的文件 但长度要和要下载的一样大 相当于一个容器 * * @param name * @param len * @throws IOException */ public void setFileSize(String name, int len) throws IOException { RandomAccessFile raf = new RandomAccessFile(name, "rw"); raf.setLength(len); raf.close(); } /** * 得到文件的总长度 * * @return * @throws IOException */ public int getContentLength() { try { if (contentLength == -1) { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5000); conn.setRequestMethod("GET"); int code = conn.getResponseCode(); if (code == 200) { String urlPath = conn.getURL().getFile(); String fileFullName = urlPath.substring(urlPath.lastIndexOf("/") + 1); if (name == null || "".equals(name)) { name = fileFullName; } contentLength = conn.getContentLength(); } } } catch (MalformedURLException e) { e.printStackTrace(); } catch (ProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return contentLength; } /** * 下载的线程 * * @author Administrator * */ class MyThread extends Thread { private int threadId; private int start; private int end; private String name; public MyThread(int threadId, int start, int end, String name) { super(); this.threadId = threadId; this.start = start; this.end = end; this.name = name; } @Override public void run() { try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5000); conn.setRequestMethod("GET"); // 重要:请求服务器下载部分文件 指定文件的位置 conn.setRequestProperty("Range", "bytes=" + start + "-" + end); // 从服务器请求全部资源返回200 如果从服务器请求部分资源 返回 206 int code = conn.getResponseCode(); InputStream is = conn.getInputStream();// 已经设置了请求的位置,返回的是当前位置对应的文件的输入流 RandomAccessFile raf = new RandomAccessFile(name, "rwd"); raf.seek(start); int len = 0; byte[] buffer = new byte[1024]; while ((len = is.read(buffer)) != -1) { if (pause) { synchronized (this) { wait(); } } raf.write(buffer, 0, len); downProgress.addAndGet(len); } is.close(); raf.close(); System.out.println("线程:" + threadId + "下载完毕"); count.incrementAndGet(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (ProtocolException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } } }
测试
<pre name="code" class="java">public static void main(String[] args) throws IOException, InterruptedException { ThreadLoad down = new ThreadLoad("http://localhost:8080/downLoad/down/qwe.mp4",null, 5); down.downLoadFile(); long preLen = 0; int len = down.getContentLength(); while (!down.finish()) { Thread.sleep(1000); long now = down.downProgress.get(); float speed = ((float)(now - preLen) / 1024); if(speed==0.0){ speed=1f; } float precent = (((float) now) / len) * 100; float total = (float)len/1024/1024; float surplusTime = ((len-now)/speed)/1000; System.out.println("已下载: " + now + "---" + precent + "%" + " 下载速度:" + speed + "k/"+total+"M 剩余"+surplusTime+"秒"); preLen = down.downProgress.get(); } }
相关文章推荐
- leetcode 34. Search for a Range | Java最短代码实现
- [BAT][JAVA]定时任务之-Quartz使用篇
- Java抽象类与接口
- 使用maven命令创建java项目
- 2016蓝桥杯假期任务之《数字游戏》
- Java基础知识之集合框架(一)
- 做一个合格的程序猿之浅析Spring IoC源码(四)分析BeanPostProcessor(1)
- eclipse中的.project 和 .classpath文件的具体作用
- Java String 类型编码转换
- Lambda表达式应用浅析
- Java基础之多线程(二)
- java写入文件(文件内容末尾追加)
- Spring mvc 跳转
- Exception in thread java.lang.IllegalThreadStateException
- Spring MVC URL路径映射
- java.io.Serializable浅析
- java web基础 (path,class_path,java_home)
- Maven Profile标签
- spring MVC +freemarker + easyui 实现sql查询和执行小工具总结
- Spring MVC的注解@