我的编程空间,编程开发者的网络收藏夹
学习永远不晚

vue 大文件分片上传(断点续传、并发上传、秒传)

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

vue 大文件分片上传(断点续传、并发上传、秒传)

对于大文件的处理,无论是用户端还是服务端,如果一次性进行读取发送、接收都是不可取,很容易导致内存问题。所以对于大文件上传,采用切块分段上传,从上传的效率来看,利用多线程并发上传能够达到最大效率。

本文是基于 springboot + vue 实现的文件上传,本文主要介绍vue实现文件上传的步骤及代码实现,服务端(springboot)的实现步骤及实现请移步本人的另一篇文章:

springboot 大文件上传、分片上传、断点续传、秒传 

上传分步:

本人分析上传总共分为:

  • MD5读取文件,获取文件的MD5编码
  • 请求服务端判断文件是否上传,如上传完成就直接返回文件地址
  • 如未上传,判断是否是断点续传
  • 判断是并发上传还是顺序上传
  • 开始分片文件上传,分片上传完成后写入已上传列表中
  • 判断是否上传完成

直接上代码

文件上传:

import md5 from 'js-md5' //引入MD5加密
import UpApi from '@/api/common.js'
import { concurrentExecution } from '@/utils/jnxh'
 

export const uploadByPieces = ({
                                 file,
                                 pieceSize = 3,
                                 concurrent = 3,
                                 success,
                                 process,
                                 error
                               }) => {
  // 如果文件传入为空直接 return 返回
  if (!file || file.length < 1) {
    return error('文件不能为空')
  }
  let fileMD5 = '' // 总文件列表
  const chunkSize = pieceSize * 1024 * 1024 // 1MB一片
  const chunkCount = Math.ceil(file.size / chunkSize) // 总片数
  const chunkList = [] // 分片列表
  let uploaded = [] // 已经上传的
  let fileType = '' // 文件类型
  // 获取md5
  
  const readFileMD5 = () => {
    // 读取视频文件的md5
    fileType = file.name.substring(file.name.lastIndexOf('.') + 1, file.name.length)
    console.log('获取文件的MD5值')
    let fileRederInstance = new FileReader()
    console.log('file', file)
    fileRederInstance.readAsBinaryString(file)
    fileRederInstance.addEventListener('load', e => {
      let fileBolb = e.target.result
      fileMD5 = md5(fileBolb)
      var index = file.name.lastIndexOf('.')
      var tp = file.name.substring(index + 1, file.name.length)
      let form = new FormData()
      form.append('filename', file.name)
      form.append('identifier', fileMD5)
      form.append('objectType', fileType)
      form.append('chunkNumber', 1)
      UpApi.uploadChunk(form).then(res => {
        if (res.skipUpload) {
          console.log('文件已被上传')
          success && success(res)
        } else {
          // 判断是否是断点续传
          if (res.uploaded && res.uploaded.length != 0) {
            uploaded = [].concat(res.uploaded)
          }
          console.log('已上传的分片:' + uploaded)
          // 判断是并发上传或顺序上传
          if (concurrent == 1 || chunkCount == 1) {
            console.log('顺序上传')
            sequentialUplode(0)
          } else {
            console.log('并发上传')
            concurrentUpload()
          }
        }
      }).catch((e) => {
        console.log('文件合并错误')
        console.log(e)
      })
    })
  }
  
  const getChunkInfo = (file, currentChunk, chunkSize) => {
    let start = currentChunk * chunkSize
    let end = Math.min(file.size, start + chunkSize)
    let chunk = file.slice(start, end)
    return {
      start,
      end,
      chunk
    }
  }
  
  const readChunkMD5 = () => {
    // 针对单个文件进行chunk上传
    for (var i = 0; i < chunkCount; i++) {
      const {
        chunk
      } = getChunkInfo(file, i, chunkSize)
 
      // 判断已经上传的分片中是否包含当前分片
      if (uploaded.indexOf(i + '') == -1) {
        uploadChunk({
          chunk,
          currentChunk: i,
          chunkCount
        })
      }
    }
  }
  
  const uploadChunk = (chunkInfo) => {
    var sd = parseInt((chunkInfo.currentChunk / chunkInfo.chunkCount) * 100)
    console.log(sd, '进度')
    process(sd)
    console.log(chunkInfo, '分片大小')
    let inde = chunkInfo.currentChunk + 1
    if (uploaded.indexOf(inde + '') > -1) {
      const {
        chunk
      } = getChunkInfo(file, chunkInfo.currentChunk + 1, chunkSize)
      uploadChunk({
        chunk,
        currentChunk: inde,
        chunkCount
      })
    } else {
      var index = file.name.lastIndexOf('.')
      var tp = file.name.substring(index + 1, file.name.length)
      // 构建上传文件的formData
      let fetchForm = new FormData()
      fetchForm.append('identifier', fileMD5)
      fetchForm.append('chunkNumber', chunkInfo.currentChunk + 1)
      fetchForm.append('chunkSize', chunkSize)
      fetchForm.append('currentChunkSize', chunkInfo.chunk.size)
      const chunkfile = new File([chunkInfo.chunk], file.name)
      fetchForm.append('file', chunkfile)
      // fetchForm.append('file', chunkInfo.chunk)
      fetchForm.append('filename', file.name)
      fetchForm.append('relativePath', file.name)
      fetchForm.append('totalChunks', chunkInfo.chunkCount)
      fetchForm.append('totalSize', file.size)
      fetchForm.append('objectType', tp)
      // 执行分片上传
      let config = {
        headers: {
          'Content-Type': 'application/json',
          'Accept': '*
  const sequentialUplode = (currentChunk) => {
    const {
      chunk
    } = getChunkInfo(file, currentChunk, chunkSize)
    let chunkInfo = {
      chunk,
      currentChunk,
      chunkCount
    }
    var sd = parseInt((chunkInfo.currentChunk / chunkInfo.chunkCount) * 100)
    process(sd)
    console.log('当前上传分片:' + currentChunk)
    let inde = chunkInfo.currentChunk + 1
    if (uploaded.indexOf(inde + '') > -1) {
      console.log('分片【' + currentChunk + '】已上传')
      sequentialUplode(currentChunk + 1)
    } else {
      let uploadData = createUploadData(chunkInfo)
      let config = {
        headers: {
          'Content-Type': 'application/json',
          'Accept': '*
  const concurrentUpload = () => {
    for (var i = 0; i < chunkCount; i++) {
      chunkList.push(Number(i))
    }
    console.log('需要上传的分片列表:' + chunkList)
    concurrentExecution(chunkList, concurrent, (curItem) => {
      return new Promise((resolve, reject) => {
        const {
          chunk
        } = getChunkInfo(file, curItem, chunkSize)
        let chunkInfo = {
          chunk,
          currentChunk: curItem,
          chunkCount
        }
        var sd = parseInt((chunkInfo.currentChunk / chunkInfo.chunkCount) * 100)
        process(sd)
        console.log('当前上传分片:' + curItem)
        let inde = chunkInfo.currentChunk + 1
        if (uploaded.indexOf(inde + '') == -1) {
          // 构建上传文件的formData
          let uploadData = createUploadData(chunkInfo)
          // 请求头
          let config = {
            headers: {
              'Content-Type': 'application/json',
              'Accept': '*
  const createUploadData = (chunkInfo) => {
    let fetchForm = new FormData()
    fetchForm.append('identifier', fileMD5)
    fetchForm.append('chunkNumber', chunkInfo.currentChunk + 1)
    fetchForm.append('chunkSize', chunkSize)
    fetchForm.append('currentChunkSize', chunkInfo.chunk.size)
    const chunkfile = new File([chunkInfo.chunk], file.name)
    fetchForm.append('file', chunkfile)
    // fetchForm.append('file', chunkInfo.chunk)
    fetchForm.append('filename', file.name)
    fetchForm.append('relativePath', file.name)
    fetchForm.append('totalChunks', chunkInfo.chunkCount)
    fetchForm.append('totalSize', file.size)
    fetchForm.append('objectType', fileType)
    return fetchForm
  }
  readFileMD5() // 开始执行代码
}

并发控制:


export function concurrentExecution(list, limit, asyncHandle) {
  // 递归执行
  let recursion = (arr) => {
    // 执行方法 arr.shift() 取出并移除第一个数据
    return asyncHandle(arr.shift()).then(() => {
      // 数组还未迭代完,递归继续进行迭代
      if (arr.length !== 0) {
        return recursion(arr)
      } else {
        return 'finish'
      }
    })
  }
  // 创建新的并发数组
  let listCopy = [].concat(list)
  // 正在进行的所有并发异步操作
  let asyncList = []
  limit = limit > listCopy.length ? listCopy.length : limit
  console.log(limit)
  while (limit--) {
    asyncList.push(recursion(listCopy))
  }
  // 所有并发异步操作都完成后,本次并发控制迭代完成
  return Promise.all(asyncList)
}

到此这篇关于vue 大文件分片上传(断点续传、并发上传、秒传)的文章就介绍到这了,更多相关vue 大文件分片上传内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

vue 大文件分片上传(断点续传、并发上传、秒传)

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

如何使用大文件上传:秒传、断点续传、分片上传方法

本篇内容介绍了“如何使用大文件上传:秒传、断点续传、分片上传方法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!秒传1、什么是秒传通俗的说,你
2023-06-15

vue怎么实现大文件分片上传与断点续传送

本文小编为大家详细介绍“vue怎么实现大文件分片上传与断点续传送”,内容详细,步骤清晰,细节处理妥当,希望这篇“vue怎么实现大文件分片上传与断点续传送”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。问题:前段时间
2023-07-02

Vue+Node怎么实现大文件上传和断点续传

本篇内容介绍了“Vue+Node怎么实现大文件上传和断点续传”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!源代码断点续传、分片上传、秒传、重
2023-06-30

Vue在大文件上传和断点续传的实现方法

本篇内容主要讲解“Vue在大文件上传和断点续传的实现方法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Vue在大文件上传和断点续传的实现方法”吧!文件上传的 2 套方案基于文件流(form-da
2023-06-20

java如何实现文件切片上传服务器+断点续传

这篇文章主要为大家展示了“java如何实现文件切片上传服务器+断点续传”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“java如何实现文件切片上传服务器+断点续传”这篇文章吧。1.定义一个实体类用
2023-06-22

SpringBoot超大文件上传实现秒传功能

这篇文章主要介绍了SpringBoot超大文件上传实现秒传功能,在实现分片上传的过程,需要前端和后端配合,比如前后端的上传块号的文件大小,前后端必须得要一致,否则上传就会有问题,需要的朋友可以参考下
2022-12-10

android文件上传示例分享(android图片上传)

主要思路是调用系统文件管理器或者其他媒体采集资源来获取要上传的文件,然后将文件的上传进度实时展示到进度条中。 主Activity代码如下:package com.guotop.elearn.activity.app.yunpan.activ
2022-06-06

编程热搜

目录