该断点下载可应用于浏览器或者迅雷等下载工具的下载,实现方式有多种多样的,本文仅仅研究了单线程的下载。迅雷等下载工具会自己主动将下载资源分块并记录每块的起始位置,然后依据系统性能。起多线程下载。

1. 基本原理

从Request Header的Range信息里面获取已经下载的文件大小,然后创建response的outputstream 向client(浏览器或者迅雷等下载工具)写,写的时候又利用header里面的“Content-Range”, 让client知道从哪个位置開始写;

读取网络资源方面,利用HttpClient模拟request请求,发起post或者get请求,仅仅是这个请求跟一般请求有点不一样:须要带上Range信息。告诉程序该从哪个位置開始读数据。

2. 须要使用的Java 组件

  • HttpServletRequest / Response
  • HttpClient
  • ServletOutputStream
  • BufferedInputStream

3. 代码实现

/**
* @desc 断点下载工具方法
* @param request
* @param response
* @param fileLength
* @param contentType
* @param fileName
* @param fileId
*/
public static void resumeDownload(HttpServletRequest request,
HttpServletResponse response, Long fileLength, String contentType,
String fileName, String fileId) {
ServletOutputStream out = null;
response.reset(); // 记录断点续传的開始点
long pos = 0;
if (null != request.getHeader("Range")) {
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
try {
pos = Long.parseLong(request.getHeader("Range")
.replaceAll("bytes=", "").replaceAll("-.*", ""));
} catch (NumberFormatException e) {
LOGGER.error(e.getMessage(), e);
pos = 0;
}
String contentRange = new StringBuffer("bytes ").append(pos + "")
.append("-").append((fileLength.intValue() - 1) + "")
.append("/").append(fileLength.intValue() + "").toString();
response.setHeader("Content-Range", contentRange);
} response.setHeader("Accept-Ranges", "bytes");
response.setHeader("Content-Length",
String.valueOf(fileLength.intValue() - pos));
response.setCharacterEncoding("UTF-8");
response.setContentType(contentType);
response.setHeader("Content-disposition", "attachment;filename=\""
+ fileName + "\"");
try {
out = response.getOutputStream();
} catch (IOException e) {
LOGGER.error(e.getMessage(), e);
} // 断点下载
CloseableHttpClient httpClient = HttpClients.createDefault(); HttpPost httpPost = new HttpPost(SysConf.getString("fezo.download.url")); List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(new BasicNameValuePair(SysConf.getString("fezo.download.param"), fileId)); HttpResponse httpResponse = null;
BufferedInputStream input = null;
try {
httpPost.setEntity(new UrlEncodedFormEntity(nvps)); httpPost.setHeader("Range", "bytes=" + pos + "-");
httpResponse = httpClient.execute(httpPost); input = new BufferedInputStream(httpResponse.getEntity().getContent()); byte[] buffer = new byte[CommonConstants.BUFFER_SIZE];
int len = -1;
while ((len = input.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
out.flush();
out.close();
input.close();
} catch (UnsupportedEncodingException e) {
LOGGER.error(e.getMessage(), e);
} catch (ClientProtocolException e) {
LOGGER.error(e.getMessage(), e);
} catch (IOException e) {
// 能够忽略这个异常。有可能是用户暂停下载,或者迅雷等下载工具分块下载
} finally {
try {
if (httpClient != null) httpClient.close();
} catch(IOException e) {
LOGGER.error(e.getMessage(), e);
}
}
}

>>>点击这里下载代码

4. 重点与难点

- 获取response的输出流程来向client提供下载功能,而不是简单的把数据写入到某个详细的文件,核心代码:out = response.getOutputStream();

- 头信息里面"Range" 和 "Conent-Range" 等信息的处理;

- 迅雷等多线程分块下载client下载的处理:还是要处理好"Range" 和 "Conent-Range" 等头部信息,迅雷会自己主动将文件内容分块、记录起始位置。

Java 实现的断点下载的更多相关文章

  1. Java实现多线程断点下载(下载过程中可以暂停)

    线程可以理解为下载的通道,一个线程就是一个文件的下载通道,多线程也就是同时开启好几个下载通道.当服务器提供下载服务时,使用下载者是共享带宽的,在优先级相同的情况下,总服务器会对总下载线程进行平均分配. ...

  2. Java之多线程断点下载的实现

    RandomAccessFile类: 此类的实例支持对随机訪问文件的读取和写入.随机訪问文件的行为相似存储在文件系统中的一个大型 byte 数组. 存在指向该隐含数组.光标或索引,称为文件指针.输入操 ...

  3. 【Java EE 学习 22 下】【单线程下载】【单线程断点下载】【多线程下载】

    一.文件下载简述 1.使用浏览器从网页上下载文件,Servlet需要增加一些响应头信息 (1)response.setContentType("application/force-downl ...

  4. Android(java)学习笔记216:多线程断点下载的原理(Android实现)

    之前在Android(java)学习笔记215中,我们从JavaSE的角度去实现了多线程断点下载,下面从Android角度实现这个断点下载: 1.新建一个Android工程: (1)其中我们先实现布局 ...

  5. java多线程下载文件和断点下载

    多线程,断点下载文件 import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; impor ...

  6. Android(java)学习笔记159:多线程断点下载的原理(Android实现)

    之前在Android(java)学习笔记215中,我们从JavaSE的角度去实现了多线程断点下载,下面从Android角度实现这个断点下载: 1. 新建一个Android工程: (1)其中我们先实现布 ...

  7. java多线程断点下载原理(代码实例演示)

    原文:http://www.open-open.com/lib/view/open1423214229232.html 其实多线程断点下载原理,很简单的,那么我们就来先了解下,如何实现多线程的断点下载 ...

  8. Java 断点下载(下载续传)服务端及客户端(Android)代码

    原文: Java 断点下载(下载续传)服务端及客户端(Android)代码 - Stars-One的杂货小窝 最近在研究断点下载(下载续传)的功能,此功能需要服务端和客户端进行对接编写,本篇也是记录一 ...

  9. Java多线程断点下载文件

    Java实现断点续传+多线程下载 如下代码所示,每一步都有注解 思路: 通过URL连接到服务器上要下载的文件,得到文件的大小: 算出每条线程下载的开始位置和结束位置,例如,有两条线程下载100Byte ...

随机推荐

  1. Angular——内置过滤器

    基本介绍 在AngularJS中使用过滤器格式化展示数据,在“{{}}”中使用“|”来调用过滤器,使用“:”传递参数. 基本使用 过滤器可以串起来使用,只要用   |  来衔接就行了,可以将上次返回的 ...

  2. jQuery之基本选择器Practice

    一.在输入框中输入数字,点击按钮,实现对应事件的功能. html代码: <input id="txt1" type="text" value=" ...

  3. Flask框架 之重定向、cookie和session

    一.URL重定向(redirect) @app.route("/login") def login(): # 使用url_for函数通过视图函数的名字找到url路径 url = u ...

  4. CAD使用SetXData写数据(com接口)

    主要用到函数说明: MxDrawEntity::SetXData 设置实体的扩展数据,详细说明如下: 参数 说明 [in] IMxDrawResbuf* pXData 扩展数据链表 c#代码实现如下: ...

  5. JAVA程序员面试笔试宝典3

    1.什么是线程?它与进程有什么区别?为什么要使用多线程 线程是指程序在执行过程中,能够执行程序代码的一个执行单元.进程是指一段正在执行的程序. 使用多线程可以减少程序的相应时间 与进程相比,线程的创建 ...

  6. 07Microsoft SQL Server View

    Microsoft SQL Server View 1.视图 视图是一个虚拟的表,是表中的数据经过某种筛选后的显示方式,视图由预定义的查询select语句组成. 2.查看视图信息 --查询系统所有视图 ...

  7. 面向对象程序设计--Java语言第三周编程题:查找里程

    查找里程 题目内容: 下图为国内主要城市之间的公路里程: 你的程序要读入这样的一张表,然后,根据输入的两个城市的名称,给出这两个城市之间的里程. 注意:任何两个城市之间的里程都已经给出,不需要计算经第 ...

  8. layer iframe层弹出图片

    这个js是在一个layer iframe弹出层中,点击按钮弹出图片

  9. Many Equal Substrings CodeForces - 1029A (kmp next数组应用)

    题目大意 题目看样例也能猜到就是输出最短的循环串. 吐槽 明明是div3第一题为啥子还会用到kmp的知识? 解法 这个题仔细看发现是求最长可去除的后缀,也就是说去除跟下一个相同的字符串还能连接起来.这 ...

  10. Python的import module与form module import的区别

    import moduleName 如果要使用moduleName模块中的方法时,是moduleName.method(点方法), 比如moduleName中有个方法是set,则使用的是moduleN ...