在开发中,如果上传的文件过大,可以考虑分片上传,分片就是说将文件拆分来进行上传,将各个文件的切片传递给后台,然后后台再进行合并。这里切片可以理解为字符串的截取,那这里文件的话就是切分字节,一个道理
上传的时候,可能会需要一个文件的唯一 标识,在上传文件的时候也要将文件的唯一标识(文件的MD5加密文件的字符串,每个文件的唯一标识)传递给后端,后端会通过该标识返回给我们告诉我们这个文件是否已经上传过,没有这个文件就需要我们全部上传,存在了,前端就不需要再上传,这个文件上传了一部分,需要把剩余的上传
这个文件的MD5唯一标识呢,也是通过spark-md5来获取,具体步骤 :
安装
npm i spark-md5
or
pnpm add spark-md5
按需引入 ,并封装方法
可以单独建个js文件,向外暴露出去
method.js
import SparkMD5 from 'spark-md5'// 获取文件的唯一MD5标识码
export function getFileMd5(file) {return new Promise((resolve, reject) => {const fileReader = new FileReader()const spark = new SparkMD5.ArrayBuffer()fileReader.readAsArrayBuffer(file)fileReader.onload = e => {spark.append(e.target.result)let md5 = spark.end()resolve(md5)}})
}
然后我们提交的时候,我们得让后台知道提交的是哪一部分的切片,不能驴头不对马嘴,闲话不多说了,我这里把核心代码贴上,大家有点儿基础的,仔细看下就懂得了,没有很复杂
我这里用的是Vue3 + element-plus中的el-upload
<div class="index"><el-uploadv-model:file-list="fileList"class="upload-demo":auto-upload="false":limit="1":on-change="handleChange"><el-button type="primary">Click to upload</el-button></el-upload>
</div>
<script setup>
import { ref } from 'vue'
import { getFileMd5 } from './method'const fileList = ref([])// 文件上传 选择文件时触发(:on-change事件)
const handleChange = async (uploadFile, uploadFiles) => {// 文件信息let fileRaw = uploadFile.rawconsole.log(fileRaw)// 获取 文件的 MD5唯一标识码let fileMd5 = nulltry {fileMd5 = await getFileMd5(fileRaw)} catch(e) {console.error('[error]', e)}if(!fileMd5) return// 每片的大小为 5M 可调整const chunkSize = 5 * 1024 * 1024// 文件分片储存let chunkList = []function chunkPush(page = 1) {chunkList.push(fileRaw.slice((page - 1) * chunkSize, page * chunkSize))if(page * chunkSize < fileRaw.size) {chunkPush(page + 1)}}chunkPush()console.log(chunkList, 'chunkList----->>>')saveFileChunk(chunkList, fileMd5, fileRaw.name)
}
// 保存文件片段到后台
const saveFileChunk = async (chunkList, fileMd5, fileName) => {for(let i = 0; i < chunkList.length; i++) {let formData = new FormData()formData.append('chunk', i) // 当前片段的索引formData.append('chunkSize', 5 * 1024 * 1024) // 切片的文件分片大小 (就是以多少字节进行分片的,这里是5M)formData.append('chunks', chunkList.length) // 共有多少分片formData.append('file', chunkList[i]) // 当前分片的文件流formData.append('md5', fileMd5) // 整个文件的MD5唯一标识码,不是分片formData.append('name', fileName) // 文件的名称formData.append('size', chunkList[i].size) // 当前切片的大小(最后一片不一定是5M)const data = await saveFileChunk(formData)if(data && data.success) {console.log('保存成功')}}
}
</script>
灵感来自:# vue 实现文件切上传