DownloadClient  是模拟前端,若前端实现需要worker线程JS插件方法
DownLoadController 是后端服务

package org.xxx.wx.web;import org.apache.commons.io.FileUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.concurrent.*;// 模拟前端(客户端)请求
@RestController
@RequestMapping("/wx/downloadclient")
public class DownloadClient {private static final Logger LOGGER = LoggerFactory.getLogger(DownloadClient.class);private final static long PER_PAGE = 1024L * 1024L * 50L;private final static String DOWN_PATH = "D:\\fileItem";ExecutorService taskExecutor = Executors.newFixedThreadPool(10);@RequestMapping("/downloadFile")public String downloadFile() {// 探测下载FileInfo fileInfo = download(0, 10, -1, null);if (fileInfo != null) {long pages =  fileInfo.fSize / PER_PAGE;for (long i = 0; i <= pages; i++) {Future<FileInfo> future = taskExecutor.submit(new DownloadThread(i * PER_PAGE, (i + 1) * PER_PAGE - 1, i, fileInfo.fName));if (!future.isCancelled()) {try {fileInfo = future.get();} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}}}return System.getProperty("user.home") + "\\Downloads\\" + fileInfo.fName;}return null;}class FileInfo {long fSize;String fName;public FileInfo(long fSize, String fName) {this.fSize = fSize;this.fName = fName;}}/*** 根据开始位置/结束位置* 分片下载文件,临时存储文件分片* 文件大小=结束位置-开始位置** @return*/private FileInfo download(long start, long end, long page, String fName) {File dir = new File(DOWN_PATH);if (!dir.exists()) {dir.mkdirs();}// 断点下载File file = new File(DOWN_PATH, page + "-" + fName);if (file.exists() && page != -1 && file.length() == PER_PAGE) {return null;}try {HttpClient client = HttpClients.createDefault();HttpGet httpGet = new HttpGet("http://127.0.0.1:8080/wx/downloadmain/download");httpGet.setHeader("Range", "bytes=" + start + "-" + end);HttpResponse response = client.execute(httpGet);String fSize = response.getFirstHeader("fSize").getValue();fName = URLDecoder.decode(response.getFirstHeader("fName").getValue(), "UTF-8");HttpEntity entity = response.getEntity();InputStream is = entity.getContent();FileOutputStream fos = new FileOutputStream(file);byte[] buffer = new byte[1024];int ch;while ((ch = is.read(buffer)) != -1) {fos.write(buffer, 0, ch);}is.close();fos.flush();fos.close();// 最后一个分片if (end - Long.parseLong(fSize) > 0) {// 开始合并文件mergeFile(fName, page);}return new FileInfo(Long.parseLong(fSize), fName);} catch (IOException e) {e.printStackTrace();}return null;}private void mergeFile(String fName, long page) {File file = new File(DOWN_PATH, fName);try {BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(file));for (long i = 0; i <= page; i++) {File tempFile = new File(DOWN_PATH, i + "-" + fName);while (!file.exists() || (i != page && tempFile.length() < PER_PAGE)) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}byte[] bytes = FileUtils.readFileToByteArray(tempFile);os.write(bytes);os.flush();tempFile.delete();}File testFile = new File(DOWN_PATH, -1 + "-null");testFile.delete();os.flush();os.close();} catch (IOException e) {e.printStackTrace();}}/*** 获取远程文件尺寸*/private long getRemoteFileSize(String remoteFileUrl) throws IOException {long fileSize = 0;HttpURLConnection httpConnection = (HttpURLConnection) new URL(remoteFileUrl).openConnection();//使用HEAD方法httpConnection.setRequestMethod("HEAD");int responseCode = httpConnection.getResponseCode();if (responseCode >= 400) {LOGGER.debug("Web服务器响应错误!");return 0;}String sHeader;for (int i = 1;; i++) {sHeader = httpConnection.getHeaderFieldKey(i);if (sHeader != null && sHeader.equals("Content-Length")) {LOGGER.debug("文件大小ContentLength:" + httpConnection.getContentLength());fileSize = Long.parseLong(httpConnection.getHeaderField(sHeader));break;}}return fileSize;}class DownloadThread implements Callable<FileInfo> {long start;long end;long page;String fName;public DownloadThread(long start, long end, long page, String fName) {this.start = start;this.end = end;this.page = page;this.fName = fName;}@Overridepublic FileInfo call() {return download(start, end, page, fName);}}
}
package org.xxx.wx.web;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;//后端下载服务
@Controller
@RequestMapping("/wx/downloadmain")
public class DownLoadController {private static final String UTF8 = "UTF-8";@RequestMapping("/download")public void downLoadFile(HttpServletRequest request, HttpServletResponse response) throws IOException {File file = new File("D:\\小黄人大眼萌:神偷奶爸前传.2022.HD.1080P.中英双字.mkv");response.setCharacterEncoding(UTF8);InputStream is = null;OutputStream os = null;try {// 分片下载 Range表示方式 bytes=100-1000  100-long fSize = file.length();response.setContentType("application/x-download");String fileName = URLEncoder.encode(file.getName(), UTF8);response.addHeader("Content-Disposition", "attachment;filename=" + fileName);// 支持分片下载response.setHeader("Accept-Range", "bytes");response.setHeader("fSize", String.valueOf(fSize));response.setHeader("fName", fileName);long pos = 0, last = fSize - 1, sum = 0;if (null != request.getHeader("Range")) {response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);String numberRange = request.getHeader("Range").replaceAll("bytes=", "");String[] strRange = numberRange.split("-");if (strRange.length == 2) {pos = Long.parseLong(strRange[0].trim());last = Long.parseLong(strRange[1].trim());if (last > fSize-1) {last = fSize - 1;}} else {pos = Long.parseLong(numberRange.replaceAll("-", "").trim());}}long rangeLength = last - pos + 1;String contentRange = new StringBuffer("bytes").append(pos).append("-").append(last).append("/").append(fSize).toString();response.setHeader("Content-Range", contentRange);response.setHeader("Content-Length", String.valueOf(rangeLength));os = new BufferedOutputStream(response.getOutputStream());is = new BufferedInputStream(new FileInputStream(file));is.skip(pos);byte[] buffer = new byte[1024];int length = 0;while (sum < rangeLength) {int readLength = (int) (rangeLength - sum);length = is.read(buffer, 0, (rangeLength - sum) <= buffer.length ? readLength : buffer.length);sum += length;os.write(buffer,0, length);}System.out.println("下载完成");}finally {if (is != null){is.close();}if (os != null){os.close();}}}
}

Springboot分片下载实现相关推荐

  1. SpringBoot Java实现Http方式分片下载断点续传+实现H5大视频渐进式播放

    项目Git地址:h5-video 一.功能目的 SpringBoot 实现Http分片下载断点续传,从而实现H5页面的大视频播放问题,实现渐进式播放,每次只播放需要播放的内容就可以了,不需要加载整个文 ...

  2. SpringBoot分片上传、断点续传、大文件极速秒传功能(典藏版)

    SpringBoot分片上传.断点续传.大文件极速秒传功能,这篇都帮你搞定!(典藏版) Java研发军团 2023-02-03 21:00 文件上传是一个老生常谈的话题了,在文件相对比较小的情况下,可 ...

  3. python写http文件下载器_http分片请求-python分片下载文件

    源文件 http://theday.guohongfu.top/letter.txt内容为abcdefghijklmnopqrstuvwxyz 获取第20字节及以后的内容import requests ...

  4. 用Electron开发企业网盘(二)--分片下载

    书接上文,背景见:https://www.cnblogs.com/shawnyung/p/10060119.html HTTP请求头  Range 请求资源的部分内容(不包括响应头的大小),单位是by ...

  5. python多进程断点续传分片下载器

    python多进程断点续传分片下载器 标签:python 下载器 多进程 因为爬虫要用到下载器,但是直接用urllib下载很慢,所以找了很久终于找到一个让我欣喜的下载器.他能够断点续传分片下载,极大提 ...

  6. python 断点下载_python多进程断点续传分片下载器

    标签:python 下载器 多进程 因为爬虫要用到下载器,但是直接用urllib下载很慢,所以找了很久终于找到一个让我欣喜的下载器.他能够断点续传分片下载,极大提高下载速度. #! /usr/bin/ ...

  7. javascript 大文件下载,分片下载,断点续传

    javascript 大文件下载,分片下载,断点续传 文章目录 javascript 大文件下载,分片下载,断点续传 1:获取文件大小: 2:切片下载 3:合并数据 4:下载到本地 5:成功 6:完整 ...

  8. SpringBoot强制下载文件

    SpringBoot强制下载文件 关键代码 File pdfFile=new File(文件路径);response.setContentType("application/force-do ...

  9. Java Web 实现文件多线程分片下载方案

    背景需求 最近发现系统中有不少功能的下载文件涉及到较大文件 当超过1G的文件下载时,直接通过浏览器下载,可能出现下载失败现象 下载失败表现为下载文件损坏,或重复重试下载 大文件的下载会因为网络波动.会 ...

最新文章

  1. python while循环语句-谈谈Python中的while循环语句
  2. docker下安装Nginx的方法
  3. 找到指定的新类型字符
  4. keras:Sequential API 和 Function API
  5. hive币2021年预计涨到多少_星时代云播|IPFS/Filecoin的价值被严重低估, FIL能不能涨到300美金?...
  6. 腾讯广告的多媒体AI技术实战
  7. android adb调试驱动,安卓手机上的调试工具adb驱动要怎么安装 手机安装adb驱动怎么做 - 驱动管家...
  8. 2022年最新版黑马程序员Java学习路线
  9. 根据经纬度调用Google地图显示对应位置
  10. Heat模板及简单应用
  11. watch事件监听三种写法
  12. Spring AOP 切面@Around注解的具体使用
  13. PHPMyWind编辑器支持一键粘贴
  14. serialport串口通信
  15. 二手iPhone手机选购指南,花小钱办大事
  16. Windows10 WSL2 安装 Ubuntu20.04LTS
  17. el-table横向滚动时表头与内容串位问题
  18. 如何批量提取文件名到excel表
  19. 一个网安博士生的收藏夹
  20. 《简读中国史》笔记——关于李约瑟问题的思考

热门文章

  1. Vue3新特性和使用方法系统总结
  2. 皮带秤 算法_双通道电子皮带秤速度新算法的研究.pdf
  3. 【数电】Verilog GDL 语言
  4. 【QT5】QPixmap的使用
  5. Python——模块(Module)和包(Package)
  6. C++轻量级界面开发框架ImGUI介绍
  7. 微信公众号之开发者工具
  8. [面试 ] js 前序中序 后序
  9. jmc、jcmd和jfr介绍
  10. 「2017 山东三轮集训 Day1」Flair