大文件-分片下载

0.需求背景

  1. 文件过大,单次文件流数据过多
  2. 需要有下载进度
  3. 需要提高下载速度

1.大文件下载的解决思路

  1. 获取文件大小,根据实际网络情况设置分片大小,确定份数
  2. 根据分片的大小索引,获取分片的流数据
  3. 所有的分片下载后,合并成最终文件

2.核心代码参考

前端 vue3
const downFile = async () => {  progress.value = 0;  finalFine.value = 0;  //获取文件的大小  let {fileName, contentLength} = await getFileSize();  //根据大小,去获取  let RANGE_SIZE = 1024 * 1024  let total = Math.ceil(contentLength / RANGE_SIZE);//向上取整  let fileArr = []  for (let i = 0; i < total; i++) {  let start = i * RANGE_SIZE  let end = start + RANGE_SIZE - 1  let range = end >= contentLength ? contentLength - start : RANGE_SIZE  fileArr.push({  index: i,  start: start,  end: end,  range: range,  chunk: undefined,  downloadTimes: 0  })  }  getFileChunkArray(fileArr, total, fileName);  
}  async function getFileSize() {  //获取文件的大小  let response = await axios({  method: 'get',  url: 'bigfile/getFileSize',  params: {}  })  let result = response.data;  let contentLength = result.contentLength;  let fileName = result.fileName;  console.log("contentLength: ", contentLength);  return {fileName: fileName, contentLength: contentLength}  
}  const getFileChunkArray = async (fileArr, total, fileName) => {  let pool = [] // 并发池  const max = 10 // 并发池异步操作的数量 ★ 设置太大或者太小,都不合适,会引起并发问题  let failList = [] // 下载失败的文件列表  let finish = 0  // 下载完成的数量  if (fileArr.length === 0) {  fineList.sort((a, b) => a.index - b.index);  let arrayBufferArray = fineList.map(item => item.chunk);  const blob = new Blob(arrayBufferArray, {type: 'application/octet-stream'});  const a = document.createElement('a');  a.href = URL.createObjectURL(blob);  a.download = fileName;  a.click();  }  for (const item of fileArr) {  let index = item.index  let start = item.start  let end = item.end  let range = item.range  let downloadTimes = item.downloadTimes  if (downloadTimes > 5) {  console.log("异常,已执行超过5次 ----- ")  break  }  console.log("range: ", index, `bytes=${start}-${end}`, range);  let res = axios({  method: 'get',  url: 'bigfile/download',  params: {  index: index,  start: start,  end: end,  range: range,  },  responseType: 'blob'  })  // 把下载文件的异步操作放入并发池里  pool.push(res)  if (pool.length === max) {  // 每当并发池跑完一个任务,就再塞入一个任务  await Promise.race(pool)  }  res.then((response) => {  let clip = response.data;  fineList.push({...item, chunk: clip})  finalFine.value++  progress.value = Math.round((finalFine.value) / total * 10000) / 100  // console.log('response: ', response)  console.log('下载进度 ----- ', finalFine.value, total, progress.value + '%')  }).catch((response) => {  console.log('response-error: ', response)  // 请求失败,从并发池里移除,添加到失败的文件列表  const index = pool.findIndex(it => it === res)  pool.splice(index, 1)  item.downloadTimes++;  failList.push(item)  }).finally(() => {  finish++  // 如果请求都完成了,递归调用自己,把下载失败的文件列表再下载一次  if (finish === fileArr.length) {  getFileChunkArray(failList, total, fileName);  }  })  }  
}  
后端java
/**  * 获取文件大小  *  * @param request 请求  * @return {@link JSONObject }  * @author Ysy  **/@RequestMapping(value = "/getFileSize", method = RequestMethod.GET)  
public JSONObject getFileSize(HttpServletRequest request) {  JSONObject result = new JSONObject();  String filePath = "D:\\" + downloadFile;  System.out.println(filePath);  File file = new File(filePath);  long contentLength = 0;  if (file.exists()) {  contentLength = file.length();  }  result.put("contentLength", contentLength);  result.put("fileName", downloadFile);  return result;  
}  /**  * 下载  *  * @param request  请求  * @param response 响应  * @param index    指数  * @param start    开始  * @param end      结束  * @param range    范围  * @return {@link ResponseEntity }  * @author Ysy  **/@RequestMapping(value = "download", method = RequestMethod.GET)  
public ResponseEntity download(HttpServletRequest request, HttpServletResponse response,  @RequestParam(value = "index", defaultValue = "") long index,  @RequestParam(value = "start", defaultValue = "") long start,  @RequestParam(value = "end", defaultValue = "") long end,  @RequestParam(value = "range", defaultValue = "") int range  
) throws IOException {  String filePath = "D:\\" + downloadFile;  File file = new File(filePath);  if (!file.exists()) {  }  System.out.println(index);  // 返回 ResponseEntity    try (  FileInputStream fis = new FileInputStream(file);  FileChannel channel = fis.getChannel()) {  // 设置起始位置  channel.position(start);  ByteBuffer buffer = ByteBuffer.allocate(range);  int bytesRead = channel.read(buffer);  if (bytesRead > 0) {  buffer.flip();  byte[] data = new byte[bytesRead];  buffer.get(data);  HttpHeaders headers = new HttpHeaders();  headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);  headers.setContentLength(bytesRead);  return new ResponseEntity<>(data, headers, HttpStatus.OK);  } else {  return new ResponseEntity<>(HttpStatus.NO_CONTENT);  }  }  
}
效果

在这里插入图片描述

4.案例源码

百度网盘 链接:https://pan.baidu.com/s/15TZCM4dfgDRRBneyHJEkaQ

码微信小程序。获取 提取码

大文件 分片下载.png|600

分片下载和A标签下载对比

1. 基本概念

- 分片下载:

  • 分片下载是一种将文件分割成多个部分(片)进行下载的技术。它通过多线程或多任务的方式,同时从服务器获取文件的不同部分。例如,一个大文件被分成10个部分,程序可以同时开启多个连接,分别下载这10个部分,然后在本地将这些部分组合成完整的文件。这种方式可以充分利用网络带宽,提高下载速度。在一些专业的下载工具(如迅雷)中,就广泛应用了分片下载技术。

- A标签下载:

  • <a>标签是HTML中的超链接标签。当使用<a>标签进行下载时,用户点击链接后,浏览器会根据链接指向的资源类型和服务器的配置,尝试以默认的方式下载文件。例如,<a href="example.pdf" download>下载文件</a>,当用户点击这个链接时,浏览器会开始下载example.pdf文件。它的下载过程相对比较简单直接,通常是单线程的,由浏览器直接处理下载请求。

1. 下载速度

- 分片下载:

  • 由于采用多线程或多任务方式,多个分片可以同时下载,能够更好地利用网络带宽。特别是在下载大型文件和网络环境较好的情况下,分片下载可以显著提高下载速度。例如,对于一个1GB的文件,如果服务器和网络允许,分片下载可以同时从服务器获取多个部分,每个部分都能占用一定的带宽进行传输,从而加快整体下载进度。

- A标签下载:

  • 通常是单线程下载,速度主要取决于网络带宽以及服务器对该文件下载的限制。对于小文件,单线程下载可能足够快,但对于大型文件,其下载速度可能会受到限制,因为它无法像分片下载那样同时获取文件的多个部分来充分利用带宽。

2. 资源占用情况

- 分片下载:

  • 因为涉及多个线程或任务同时运行,会占用较多的系统资源,如CPU和内存。多个线程的调度和文件分片的管理都需要一定的系统资源支持。例如,在进行大量分片下载时,可能会导致计算机的CPU使用率升高,内存占用量增大,从而可能会影响计算机的其他操作性能。

- A标签下载:

  • 资源占用相对较少,主要是浏览器本身的资源占用。它只是通过浏览器的单线程下载机制进行文件下载,不需要额外的复杂线程管理和文件分片组合操作,所以对系统资源的需求比较低。

3. 稳定性和可靠性

- 分片下载:

  • 相对复杂的下载过程可能会导致一些稳定性问题。例如,如果其中一个分片的下载出现错误(如网络中断、服务器故障等),可能需要重新下载该分片或者采取一些错误恢复措施。不过,好的分片下载工具会有相应的机制来处理这些情况,比如重试下载出错的分片一定次数后,如果还不行,可能会从其他服务器或节点获取该分片。

- A标签下载:

  • 比较简单直接,相对更稳定。如果下载过程中出现问题(如网络中断),浏览器通常会提供简单的恢复机制,如重新开始下载或者提示用户是否继续等。因为它没有复杂的分片管理,所以出现错误后的恢复相对比较容易理解和操作。

4. 适用场景

- 分片下载:

  • 适用于大型文件的下载,尤其是在需要快速下载并且网络条件允许的情况下。例如,下载大型的软件安装包、高清视频文件等。同时,在一些需要对下载过程进行更精细控制的场景下也很有用,比如暂停、恢复各个分片的下载,或者设置不同分片的优先级等。

- A标签下载:

  • 适合于小文件的下载,如文档、图片等。对于一些简单的文件下载需求,不需要复杂的下载工具,使用<a>标签就可以方便地实现文件下载。而且,在网页开发中,对于大多数普通的文件下载链接,<a>标签是一种简单直接的实现方式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/442831.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机毕业设计 基于Flask+vue的博客系统的设计与实现 Python毕业设计 Python毕业设计选题 Flask框架 Vue【附源码+安装调试】

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

Python绘制--绘制心形曲线

今天&#xff0c;我们将通过Python代码来绘制一个心形曲线&#xff0c;这是一个经典的数学表达。 一、心形曲线的数学原理 心形曲线&#xff0c;也被称为心脏曲线&#xff0c;是一个代数曲线&#xff0c;可以通过参数方程定义。其数学表达式如下&#xff1a; x16sin⁡3(t)x16…

1,STM32CubeMX生成第一个freeRTOS工程

1&#xff0c;前言 本章内容是CubeMX工程配置freeRTOS的demo工程&#xff0c;后续其他本专栏文章中不再提及&#xff0c;默认在本章内容上完成。 单片机型号&#xff1a;STM32F407 编程环境 &#xff1a;STM32CubeMX Keil v5 2&#xff0c;STM32CubeMX新建工程 双击打开ST…

新增数据集 SDK、“关系抽取”文本标注、优化模型监控和管理|ModelWhale 版本更新

ModelWhale 带来了新一轮的版本更新&#xff0c;期待为大家带来更优质的使用体验。 本次更新中&#xff0c;ModelWhale 主要进行了以下功能迭代&#xff1a; 数据管理&#xff1a;新增 mw_python_sdk 支持通过查看、下载、制作、更新数据集 文本标注&#xff1a;新增“关系抽取…

最新版本SkyWalking【10.1.0】部署

这里写目录标题 前言前置条件启动Skywalking下载解压启动说明 集成Skywalking Agent下载Agent在IDEA中添加agent启动应用并访问SpringBoot接口 说明 前言 基于当前最新版10.1.0搭建skywalking 前置条件 装有JDK11版本的环境了解SpringBoot相关知识 启动Skywalking 下载 地…

停车位识别数据集 图片数量12416张YOLO,xml和txt标签都有; 2类类别:space-empty,space-occupied;

YOLO停车位识别 图片数量12416张&#xff0c;xml和txt标签都有&#xff1b; 2类类别&#xff1a;space-empty&#xff0c;space-occupied&#xff1b; 用于yolo&#xff0c;Python&#xff0c;目标检测&#xff0c;机器学习&#xff0c;人工智能&#xff0c;深度学习&#xff0…

WordPress修改固定链接后301的重定向方法

网站改版实际上是很忌讳的&#xff0c;尤其是针对已被搜索引擎收录的网站&#xff0c;新站不用考虑这些问题&#xff0c;而已经收录的网站网页在不遵守搜索引擎规则的前提下&#xff0c;是会被降权&#xff0c;关键词排名下滑、流量IP会被剥夺、收录会减少 、业务成交量会急剧下…

Java—逻辑控制与输入输出

各位看官&#xff1a;如果您觉得这篇文章对您有帮助的话 欢迎您分享给更多人哦 感谢大家的点赞收藏评论&#xff0c;感谢您的支持&#xff01;&#xff01;&#xff01; 一.顺序结构&#xff1a; 我每天起床&#xff0c;躺在床上玩手机&#xff0c;然后吃中午饭&#xff0c;睡…

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(2)Keras

文章目录 前言一、Keras二、使用Kears 估计回归问题的神经网络1. 载入、处理数据2. 数据预处理&#xff1a;归一化3. 设定一系列随机数种子4. 定义了一个简单的深度神经网络5. 训练模型6. 查看训练结果7. 使用最优轮数&#xff08;index1&#xff09;重新估计 此神经网络模型8.…

Authentication Lab | Timing Attacks

关注这个靶场的其它相关笔记&#xff1a;Authentication Lab —— 靶场笔记合集-CSDN博客 0x01&#xff1a;Timing Attacks 前情提要 由于软件系统对不同输入处理时间的差异&#xff0c;可能会导致系统存在侧信道攻击的隐患。比如&#xff0c;如果输入的是无效的用户名&#x…

通信工程学习:什么是三网融合

三网融合 三网融合&#xff0c;又称“三网合一”&#xff0c;是指电信网、广播电视网、互联网在高层业务应用上的深度融合。这一概念在近年来随着信息技术的快速发展而逐渐受到重视&#xff0c;并成为推动信息化社会建设的重要力量。以下是对三网融合的详细解释&#xff1a; 一…

LeetCode题练习与总结:生命游戏--289

一、题目描述 根据 百度百科 &#xff0c; 生命游戏 &#xff0c;简称为 生命 &#xff0c;是英国数学家约翰何顿康威在 1970 年发明的细胞自动机。 给定一个包含 m n 个格子的面板&#xff0c;每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态&#xff1a; 1 即…

HTML图形

HTML图形 1. HTML5 Canvas2.HTML5 内联 SVG3.HTML 5 Canvas vs. SVG 1. HTML5 Canvas HTML5 的 canvas 元素使用 JavaScript 在网页上绘制图像。画布是一个矩形区域&#xff0c;您可以控制其每一像素。canvas 拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法。 1、创建…

想要成为独立游戏作者 :通关!游戏设计之道 1-1

1-1代表该书《通关&#xff01;游戏设计之道》第一章的第一篇文章 游戏是什么&#xff1f; 小时候我是先有卡带游戏机后接触的平板电脑和手机&#xff0c;起初我认为游戏是带给人快乐的&#xff0c;我就喜欢游戏里面各种有趣的玩法&#xff0c;各种友爱的画风&#xff0c;尤其…

哈夫曼编码

文章目录 &#x1f34a;自我介绍&#x1f34a;哈夫曼编解码&#x1f34a;哈夫曼树介绍&#x1f34a;哈夫曼编码思想 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以&#xff1a;点赞关注评论收藏&#xff08;一键四连&#xff09;哦~ &#x1f34a;自我介绍 Hello,大家…

AI 正在颠覆编程,程序员的出路在哪里?

AI 正在颠覆编程&#xff0c;程序员的出路在哪里&#xff1f; AI 的飞速发展&#xff0c;让程序员群体感受到了前所未有的压力。我们的工作&#xff0c;真的会被 AI 取代吗&#xff1f;未来的职业发展方向究竟在哪&#xff1f;我们应该害怕&#xff0c;还是应该拥抱这种变化&a…

Spring Boot ⽇志

目录 1.⽇志使⽤ 2.⽇志级别 3.⽇志配置 3.1配置⽇志级别 3.2⽇志持久化 3.3配置⽇志⽂件分割 4.更简单的⽇志输出 1.⽇志使⽤ 在使用之前我们先来了解一下为什么要使用&#xff1f; ⽇志的⽤途 1.系统监控 我们可以通过⽇志记录这个系统的运⾏状态&#xff0c;对数…

The legacy JS API is deprecated and will be removed in Dart Sass 2.0

The legacy JS API is deprecated and will be removed in Dart Sass 2.0 更新了sass版本后&#xff0c;启动项目控制台一直在报错&#xff0c;影响开发效率&#xff0c;强迫症表示忍受不了。 字面意思是&#xff1a;Sass在2.0版本将会移除legacy JS API&#xff0c;所以现在使…

Git的安装配置

目录 一、git和svn的区别是什么 二、下载Git 三、安装 四、使用 一、git和svn的区别是什么 1、git是分布式的&#xff0c;svn是集中的式的 2、git存储数据时是按元数据的方式存储&#xff0c;而svn是按文件的方式存储 3、git分支和svn的分支不一样 4、git没有全局版本号…

【Sceneform-EQR】(手势控制器实现)通过手势事件实现在AR/VR等三维场景中的控制模型旋转、平移与缩放

在Sceneform-EQR中实现旋转平移缩放手势 实现在AR/VR等三维场景&#xff0c;通过手势控制模型节点的缩放、平移和旋转。 实现思路 实现模型旋转 Sceneform-EQR(filament\opengl)中采用右手坐标系。通过欧拉角进行旋转采用Z->Y->X的顺序&#xff0c;在这里&#xff0c;…