大文件-分片上传 vue3+java

news2025/1/15 15:24:25

0.需求背景

  1. 遇到大文件上传时,会存在文件过大,后端无法一次性接受
  2. 上传过程中,异常失败后,需要重新上传,耗时
  3. 单次请求时间过长,请求受限
    分片上传,相比于普通的单线程上传,速度更快,更灵活。

1.大文件上传的解决思路

  1. 前端文件切片:把一个大文件转换成二进制内容,然后按照一个固定的大小对二进制内容进行切割,得到多个小文件,然后循环上传所有的小文件。在js中,文件File对象是Blob对象的子类,可以使用slice()方法完成对文件的切割;
  2. 后端文件合并:当所有小文件上传完成,调用接口通知后端把所有的文件按编号进行合并,组成大文件;
  3. 并发控制:结合Promise.race和异步函数实现,限制多个请求同时并发的数量,防止浏览器内存溢出;
  4. 断点续传:把所有上传失败的小文件加入一个数组里面,在所有小文件都上传结束(成功和失败都算结束)之后再上传一次上传失败了的小文件,反复执行这一步,直到所有小文件都上传成功,可以通过递归实现。

思考的点

  1. 上传多次失败的分片,如何处理?
    1. 如上思路,会自动重新上传,但是不可以无限制的一直重复上传。大概率是接口并发问题,二次上传或者调整并发量,就可以上传上去了。
    2. 提供重新上传机会,但是原则上,必须所有的分片都上传成功后,才能合并出最终的大文件。
  2. 断网重连如何处理?待实现
    1. 出现请求失败的请求,则循环停止,暂停后面的请求了,直到网络连接后再继续上传!定时器,判断网络是否可行。
    2. 暴力的方案:界面检测到没有网络了,直接提示让客户重新上传,原来上传的作废。
  3. 上传一半,浏览器关闭,已上传的切片垃圾数据,如何处理?
    1. 方案1,界面销毁,触发销毁事件,告知后台,删除掉剩下的文件
    2. 方案2,后台定时检查分片数据。如果文件夹的创建日期是隔天的,则删除。
    3. 客户要二次上传,就重新进界面了
  4. 进度显示,切片的上传返回结果

3.核心代码参考

前端大文件切片

// 文件分片  
let hash = 0 // 切片序号  
let size = 1024 * 50 // 切片大小  
let fileArr = []  
  
total.value = Math.ceil(file.size / size)  
console.log('total: ', total)  
  
for (let i = 0; i < file.size; i = i + size) {  
  fileArr.push({  
    hash: hash++,  
    chunk: file.slice(i, i + size),  
    uploadTimes: 0  
  })  
  progress.value = Math.round(hash / total.value * 10000) / 100  
  console.log('拆分', hash)  
  console.log('拆分进度', progress.value + '%')  
}

前端切片上传

// 遍历文件列表,上传文件  
for (let i = 0; i < list.length; i++) {  
  let item = list[i]  
  if (item.uploadTimes > 5) {  
    errorList.push(item)  
    console.log('item.uploadTimes: ', item.uploadTimes)  
    continue  
  }  
  item.uploadTimes = item.uploadTimes + 1//记录  
  
  let formData = new FormData()  
  formData.append('filename', file.name)  
  formData.append('hash', item.hash)  
  formData.append('dir', uuid)  
  formData.append('chunk', item.chunk)  
  console.log('上传', item.hash)  
  
  // 上传  
  let res = axios({  
    method: 'post',  
    url: 'bigfile/upload',  
    data: formData  
  })  
  // 把上传文件的异步操作放入并发池里  
  pool.push(res)  
  if (pool.length === max) {  
    // 每当并发池跑完一个任务,就再塞入一个任务  
    await Promise.race(pool)  
  }  
  
  res.then((response) => {  
    let status = response.data.status  
    if (status == '201') {  
      // 请求成功,从并发池里移除  
      const index = pool.findIndex(it => it === res)  
      pool.splice(index, 1)  
      finalFine.value++  
      progress.value = Math.round(finalFine.value / total.value * 10000) / 100  
      console.log('response: ', response)  
      console.log('上传进度 ----- ', finalFine.value, total.value, progress.value + '%')  
    } else {  
      //上传有问题  
      const index = pool.findIndex(it => it === res)  
      pool.splice(index, 1)  
      failList.push(item)  
    }  
  }).catch((response) => {  
    console.log('response-error: ', response)  
    // 请求失败,从并发池里移除,添加到失败的文件列表  
    const index = pool.findIndex(it => it === res)  
    pool.splice(index, 1)  
    failList.push(item)  
  }).finally(() => {  
    finish++  
    // 如果请求都完成了,递归调用自己,把上传失败的文件列表再上传一次  
    if (finish === list.length) {  
      uploadFileChunks(failList, uuid)  
    }  
  })  
}

后端切片合并

// 创建目标文件  
RandomAccessFile writeFile = new RandomAccessFile(targetFile, "rw");  
  
// 位置起始点  
long position = 0L;  
for (String tempFilename : fileNames) {  
    // System.out.println(tempFilename);  
    File sourceFile = new File(parentDir, tempFilename);// 切片文件  
    RandomAccessFile readFile = new RandomAccessFile(sourceFile, "rw");  
    int chunksize = 1024 * 3;  
    byte[] buf = new byte[chunksize];  
    writeFile.seek(position);  
    int byteCount = 0;  
    while ((byteCount = readFile.read(buf)) != -1) {  
       if (byteCount != chunksize) {  
          byte[] tempBytes = new byte[byteCount];  
          System.arraycopy(buf, 0, tempBytes, 0, byteCount);  
          buf = tempBytes;  
       }  
       writeFile.write(buf);// 写入  
       position = position + byteCount;  
    }  
    readFile.close();  
}  
writeFile.close();

4.案例源码

百度网盘 链接:https://pan.baidu.com/s/1wMJoE0ETiSPHniJLV5IPZA

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

大文件 分片上传.png|600

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

利士策分享,婚姻为何被称为大事?

利士策分享&#xff0c;婚姻为何被称为大事&#xff1f; 在历史的长河中&#xff0c;婚姻一直被视为人生中的头等大事&#xff0c;这一观念跨越时空&#xff0c;深深植根于各种文化和社会结构中。 古人为何将婚姻称为“大事”&#xff0c;这背后蕴含着丰富的社会、文化和心理寓…

JUC高并发编程6:Callable接口

1 创建线程的方式 在 Java 中&#xff0c;创建线程的方式主要有以下几种&#xff1a; 继承 Thread 类&#xff1a; 通过继承 Thread 类并重写 run() 方法来创建线程。示例代码&#xff1a;class MyThread extends Thread {Overridepublic void run() {// 线程执行的代码} }pub…

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

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

如何运行服务器上的web页面,打开Outlook 365的全球离线通讯簿功能?

&#x1f3c6;本文收录于《全栈Bug调优(实战版)》专栏&#xff0c;主要记录项目实战过程中所遇到的Bug或因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&am…

Linux入门攻坚——35、Linux防火墙-iptables-1

Firewall&#xff1a;防火墙&#xff0c;就是一个隔离工具。工作于主机或网络的边缘&#xff0c;对于进出本主机或网络的报文根据事先定义好的检查规则做匹配检测&#xff0c;对于能够被规则所匹配到的报文做出相应处理的组件&#xff1a;这个组件可以是硬件&#xff0c;也可以…

WPS的JS宏实现删除某级标题下的所有内容

想要删除Word文档中&#xff0c;包含特定描述的标题下所有内容&#xff08;包含各级子标题以及正文描述&#xff09;。 例如下图中&#xff0c;想删除1.2.1.19.1业务场景下所有内容&#xff1a; 简单版&#xff1a; 删除光标停留位置的大纲级别下所有的内容。实现的JS代码如下…

机器学习笔记-2

文章目录 一、Linear model二、How to represent this function三、Function with unknown parameter四、ReLU总结、A fancy name 一、Linear model 线性模型过于简单&#xff0c;有很大限制&#xff0c;我们需要更多复杂模式 蓝色是线性模型&#xff0c;线性模型无法去表示…

ubuntu 开放 8080 端口快捷命令

文章目录 查看防火墙状态开放 80 端口开放 8080 端口开放 22端口开启防火墙重启防火墙**使用 xhell登录**&#xff1a; 查看防火墙状态 sudo ufw status [sudo] password for crf: Status: inactivesudo ufw enable Firewall is active and enabled on system startup sudo…

Flutter 3.24 发布:GPU模块及多视图嵌入功能

Flutter 3.24 发布&#xff1a;GPU模块及多视图嵌入功能 Flutter 3.24 带来了许多新功能和改进&#xff0c;让开发应用程序变得更加容易和有趣。这个版本重点展示了 Flutter GPU 的预览功能&#xff0c;让应用程序可以直接使用高级图形和 3D 场景功能。 此外&#xff0c;网页…

传智杯 第六届—B

题目&#xff1a; 擂台赛要开始了&#xff0c;现在有 n 名战士&#xff0c;其中第 i 名战士的战斗力为 ai​。现在准备从这些战士中挑两名战士进入擂台赛进行对战&#xff0c;由于观众们更喜欢看势均力敌的比赛&#xff0c;所以我们也要挑选两个战斗力尽可能相近的战士进行参赛…

Linux-分析 IO 瓶颈手册

分析IO瓶颈 此文主要内容&#xff1a;I/O性能重要指标、主要排查工具、主要排查手段、工具图示 磁盘 I/O 性能指标 四个核心的磁盘 I/O 指标 使用率&#xff1a;是指磁盘忙处理 I/O 请求的百分比。过高的使用率&#xff08;比如超过 60%&#xff09;通常意味着磁盘 I/O 存在…

Spring系列 Bean的生命周期

文章目录 初始化时机单例初始化流程getBeandoGetBeangetSingleton(String) 获取单例getSingleton(String, ObjectFactory) 创建单例beforeSingletonCreationcreateBeanafterSingletonCreation createBean 创建对象doCreateBeanaddSingletonFactory createBeanInstance 创建 Bea…

基于springboot vue 学生就业信息管理系统设计与实现

博主介绍&#xff1a;专注于Java&#xff08;springboot ssm springcloud等开发框架&#xff09; vue .net php phython node.js uniapp小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作☆☆☆ 精彩专栏推荐订阅☆☆☆☆…

水库大坝安全监测预警系统守护大坝安全卫士

一、系统背景 近年来&#xff0c;受全球气候变化和人类活动影响&#xff0c;极端天气发生频度强度增加&#xff0c;加之我国城市化进程中&#xff0c;水库下游人口聚集、基础设施密集&#xff0c;对水库工程安全运行提出了新的更高要求。“十四五”以来我国建成并投入使用37593…

NeRS: Neural Reflectance Surfaces for Sparse-view 3D Reconstruction in the Wild

1. 2.优点1&#xff1a;我们的方法仅依赖于近似的相机位姿估计和粗略的类别级形状模板。 3.我们的关键见解是&#xff0c;我们可以强制执行基于表面的 3D 表示&#xff0c;而不是允许广泛用于体积表示的无约束密度。重要的是&#xff0c;这允许依赖于视图的外观变化 4.更重要…

迪士尼数据泄露事件:全面审视数据安全策略与未来防护方向

迪士尼数据泄露事件概述 一、 事件背景以及影响 在全球数字化转型加速的浪潮中&#xff0c;数据安全已成为企业运营不可忽视的基石。 华特迪士尼公司&#xff0c;作为全球知名的娱乐传媒巨头&#xff0c;其数据泄露事件无疑为业界敲响了警钟。此次事件不仅揭示了数据保护的严…

从0开始下载安装并使用unity

首先我们要在浏览器上找到unity的官网 这一个就是了&#xff0c;我们点进去后是这个界面&#xff1a; 然后我们点击上面这张图的左下角的“下载Unity Hub”&#xff0c;推荐后续安装都装在D盘&#xff1a; 这里他会让我们注册一个账号&#xff0c;如果之前有的话登录就行了&am…

2024年第二届龙信杯 WP

2024年龙信杯 author&#xff1a;mumuzi date&#xff1a;2024/9/30 取证的一手更新都在自己的博客上&#xff0c;分区为Forensic&#xff0c;https://mumuzi7179.github.io/或https://mumuzi.blog/ DK盾云服务器&#xff1a;DK盾 镜像下载地址&#xff1a; https://pan.ba…

i18n多语言项目批量翻译工具(支持84种语言)

这里写自定义目录标题 打开‘i18n翻译助手’小程序快捷访问 打开‘i18n翻译助手’小程序 1.将需要翻译的json文件复制到输入框&#xff08;建议一次不要翻译过多&#xff0c;测试1000条以内没什么问题&#xff09; 2.等待翻译 3.翻译完成&#xff0c;复制结果 快捷访问

极狐GitLab 发布安全补丁版本 17.4.1、17.3.4、17.2.8

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署极狐GitLab。 学习极狐GitLab 的相关资料&#xff1a; 极狐GitLab 官网极狐…