多线程下载
2017-04-18 19:34 甘雨路 阅读(253) 评论(0) 编辑 收藏 举报<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <servlet> <servlet-name>downloadImage</servlet-name> <servlet-class>mutidownload.ImageServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>downloadImage</servlet-name> <url-pattern>*.download</url-pattern> </servlet-mapping> </web-app>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>图片下载</title> </head> <body> <div> <label>Tomcat</label><a href="http://localhost:8080/lf.download?url=http://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-6/v6.0.53/bin/apache-tomcat-6.0.53.tar.gz">下载</a><br> </div> </body> </html>
package mutidownload; import java.io.IOException; import java.nio.file.Path; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import mutidownload.util.DownUtil; public class ImageServlet extends HttpServlet{ public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String path = req.getParameter("url"); System.out.println(path); DownUtil downUtil =new DownUtil(path, "C:\\Users\\111\\Desktop\\test", 3); try { downUtil.download(); } catch (Exception e) { e.printStackTrace(); } //转发 req.getRequestDispatcher("/index.jsp").forward(req, resp); } }
package mutidownload.util; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class DownUtil { /** * 被下载文件的路径 */ private String path; /** * 下载文件存放的目录 */ private String targetFilePath; /** * 线程数量 */ private static int threadCount = 3; /** * 被下载文件的大小 */ private int connectionLength; /** * 定义下载的线程对象 */ private DownloadThread[] threads; /** * 构造方法 * @param path 要下载文件的网络路径 * @param targetFilePath 保存下载文件的目录 * @param threadCount 开启的线程数量 */ public DownUtil(String path, String targetFilePath, int threadCount) { this.path = path; this.targetFilePath = targetFilePath; this.threadCount = threadCount; } /** * 下载文件 */ public void download() throws Exception{ //连接资源 URL url = new URL(path); // 打开连接 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); // 设置请求方式 connection.setRequestMethod("GET"); // 设置超时时间 connection.setConnectTimeout(10000); // 获取响应状态码 int code = connection.getResponseCode(); if(code == 200){ //获取资源大小 connectionLength = connection.getContentLength(); System.out.println(connectionLength); //在本地创建一个与资源同样大小的文件来占位 RandomAccessFile randomAccessFile = new RandomAccessFile(new File(targetFilePath,getFileName(url)), "rw"); randomAccessFile.setLength(connectionLength); /* * 将下载任务分配给每个线程 */ //计算每个线程理论上下载的数量 int blockSize = connectionLength/threadCount; //为每个线程分配任务 for(int threadId = 0; threadId < threadCount; threadId++){ //线程开始下载的位置 int startIndex = threadId * blockSize; //线程结束下载的位置 int endIndex = (threadId+1) * blockSize -1; //如果是最后一个线程,将剩下的文件全部交给这个线程完成 if(threadId == (threadCount - 1)){ endIndex = connectionLength - 1; } //开启线程下载 new DownloadThread(threadId, startIndex, endIndex).start(); } randomAccessFile.close(); } } //下载的线程 private class DownloadThread extends Thread{ private int threadId; private int startIndex; private int endIndex; public DownloadThread(int threadId, int startIndex, int endIndex) { this.threadId = threadId; this.startIndex = startIndex; this.endIndex = endIndex; } @Override public void run() { System.out.println("线程"+ threadId + "开始下载"); try { //分段请求网络连接,分段将文件保存到本地. URL url = new URL(path); //加载下载位置的文件 File downThreadFile = new File(targetFilePath,"downThread_" + threadId+".dt"); RandomAccessFile downThreadStream = null; //如果文件存在 if(downThreadFile.exists()){ downThreadStream = new RandomAccessFile(downThreadFile,"rwd"); String startIndex_str = downThreadStream.readLine(); this.startIndex = Integer.parseInt(startIndex_str);//设置下载起点 }else{ downThreadStream = new RandomAccessFile(downThreadFile,"rwd"); } // 打开连接 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(10000); //设置分段下载的头信息。 Range:做分段数据请求用的。格式: Range bytes=0-1024 或者 bytes:0-1024 connection.setRequestProperty("Range", "bytes="+ startIndex + "-" + endIndex); System.out.println("线程_"+threadId + "的下载起点是 " + startIndex + " 下载终点是: " + endIndex); //200:请求全部资源成功, 206代表部分资源请求成功 if(connection.getResponseCode() == 206){ //获取输入流 InputStream inputStream = connection.getInputStream(); //获取前面已创建的文件. RandomAccessFile randomAccessFile = new RandomAccessFile( new File(targetFilePath,getFileName(url)), "rw"); randomAccessFile.seek(startIndex);//文件写入的开始位置. /* * 将网络流中的文件写入本地 */ byte[] buffer = new byte[1024]; int length = -1; //记录本次下载文件的大小 int total = 0; while((length = inputStream.read(buffer)) > 0){ randomAccessFile.write(buffer, 0, length); total += length; /* * 将当前现在到的位置保存到文件中 */ downThreadStream.seek(0); downThreadStream.write((startIndex + total + "").getBytes("UTF-8")); } downThreadStream.close(); inputStream.close(); randomAccessFile.close(); //删除临时文件 cleanTemp(downThreadFile); System.out.println("线程"+ threadId + "下载完毕"); }else{ System.out.println("响应码是" +connection.getResponseCode() + ". 服务器不支持多线程下载"); } } catch (Exception e) { e.printStackTrace(); } } } //删除线程产生的临时文件 private synchronized void cleanTemp(File file){ file.delete(); } //获取下载文件的名称 private String getFileName(URL url){ String filename = url.getFile(); return filename.substring(filename.lastIndexOf("/")+1); } }