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

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. PAT 甲级1135. Is It A Red-Black Tree (30)

    链接:1135. Is It A Red-Black Tree (30) 红黑树的性质: (1) Every node is either red or black. (2) The root is ...

  2. js中原型和原型链

    1.原型: 在JavaScript 中,对象被表现为prototype . 原型其实一直存在于我们接触过的任何一个对象. 2. Tip:在函数对象中也存在__proto__属性,但是查看函数对象的原型 ...

  3. HTML meta信息含义

    <meta name="viewport" content="width=device-width,initial-scale=1.0"> cont ...

  4. ANNOTATION and analyse hello1.java

    一.What is annotation? annotation的中文意思就是注解,注释的意思.注解也属于一种类型.它是在 Java SE 5.0 版本中开始引入的概念.它的形式跟接口很类似,不过前面 ...

  5. vue组件---动态组件之多标签页面

    首先看下效果图 代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> & ...

  6. HDU多校Round 8

    Solved:2 rank:141 D. Parentheses Matrix n,m有一个小于6的时候是一种构造方法 答案是n + (m - 2) / 2 (n > m) 都大于6的时候 可以 ...

  7. Bullet:关于ORACLE中的HASH JOIN的参数变化

    Oracle在7.3引入了hash join. 但是在Oracle 10g及其以后的Oracle数据库版本中,优化器,实际是CBO,也是因为HASH JOIN仅适用于CBO,在解析目标SQL时是否考虑 ...

  8. 一只小蜜蜂(hdoj 2044,动态规划递推)

    Problem Description 有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行.请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数.其中,蜂房的结构如下所示. Input 输入数据的第一行 ...

  9. Luogu P2847 [USACO20DEC]Moocast(gold)奶牛广播-金

    解题思路 要保证图是强连通的,用因为给出的边全部都是双向边.考虑树形的结构,在一棵树上的$N$个节点一定是强连通的.他们都能够互相到达.又要保证树上的$n-1$条边中的最长的一条边最小.那就用Krus ...

  10. 在Java中调用带参数的存储过程

    JDBC调用存储过程: CallableStatement 在Java里面调用存储过程,写法那是相当的固定: Class.forName(.... Connection conn = DriverMa ...