<?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);
}
}