博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java 实现的断点下载
阅读量:4332 次
发布时间:2019-06-06

本文共 3247 字,大约阅读时间需要 10 分钟。

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

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
nvps = new ArrayList
(); 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" 等头部信息,迅雷会自己主动将文件内容分块、记录起始位置。

转载于:https://www.cnblogs.com/liguangsunls/p/6858388.html

你可能感兴趣的文章
阶段3 2.Spring_04.Spring的常用注解_3 用于创建的Component注解
查看>>
阶段3 2.Spring_04.Spring的常用注解_2 常用IOC注解按照作用分类
查看>>
阶段3 2.Spring_09.JdbcTemplate的基本使用_5 JdbcTemplate在spring的ioc中使用
查看>>
阶段3 3.SpringMVC·_07.SSM整合案例_02.ssm整合之搭建环境
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第1节零基础快速入门SpringBoot2.0_3、快速创建SpringBoot应用之手工创建web应用...
查看>>
阶段3 3.SpringMVC·_07.SSM整合案例_04.ssm整合之编写SpringMVC框架
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第1节零基础快速入门SpringBoot2.0_5、SpringBoot2.x的依赖默认Maven版本...
查看>>
阶段3 3.SpringMVC·_07.SSM整合案例_08.ssm整合之Spring整合MyBatis框架
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第2节 SpringBoot接口Http协议开发实战_9、SpringBoot基础HTTP其他提交方法请求实战...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第2节 SpringBoot接口Http协议开发实战_12、SpringBoot2.x文件上传实战...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第4节 Springboot2.0单元测试进阶实战和自定义异常处理_19、SpringBoot个性化启动banner设置debug日志...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第4节 Springboot2.0单元测试进阶实战和自定义异常处理_20、SpringBoot2.x配置全局异常实战...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第5节 SpringBoot部署war项目到tomcat9和启动原理讲解_23、SpringBoot2.x启动原理概述...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第4节 Springboot2.0单元测试进阶实战和自定义异常处理_21、SpringBoot2.x配置全局异常返回自定义页面...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第8节 数据库操作之整合Mybaties和事务讲解_32..SpringBoot2.x持久化数据方式介绍...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第8节 数据库操作之整合Mybaties和事务讲解_34、SpringBoot整合Mybatis实操和打印SQL语句...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第8节 数据库操作之整合Mybaties和事务讲解_35、事务介绍和常见的隔离级别,传播行为...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第9节 SpringBoot2.x整合Redis实战_40、Redis工具类封装讲解和实战...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第9节 SpringBoot2.x整合Redis实战_37、分布式缓存Redis介绍...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第10节 SpringBoot整合定时任务和异步任务处理_42、SpringBoot常用定时任务配置实战...
查看>>