大文件上传优点:
大文件上传缺点:
大文件上传原理:
为什么要用md5
因为每个文件都会有自己专属独立的md5值,就像是每个人的身份证,比如我们在某个平台发布视频,将视频文件二次上传的时候就会遇到不容易过审的原因,同一个MD5就有很大的机率显示搬运被退回。刚好后端同学也可以通过MD5这种特性来判断上传的文件是否完整。
实现流程:
在upload组件上传文件的钩子函数beforeUpload() 中:
- 获取切片文件:设置切片文件大小、每次上传的开始字节,每次上传的结尾字节。文件切片的核心是使用Blob 对象的 slice 方法:
var blob = file.slice([start [, end [, contentType]]]};
start 和 end 代表 Blob 里的下标,表示被拷贝进新的 Blob 的字节的起始位置和结束位置。contentType 会给新的 Blob 赋予一个新的文档类型,很少使用。
- 计算分片文件的MD5
- 上传分片文件,断点续传(如何实现断点续传,关键点是后端需要记录文件文件切片的信息。用户在上传一个文件之前,先询问服务器,当前文件是否存在已经上传完毕的切片,如果存在的话,需要返回切片信息。前端根据返回的信息,调整当前的进度,上传未完成的切片)
- 检验分片数量及上传的结果,全部上传,文件合并:
部分代码1:
export default class Project extends React.PureComponent { construction (props){ this.state({ file: {}, fileplanNumber: 0, // 上传文件进度的百分比 fileUploadState: '', // 上传文件的状态,fail失败, success成功 interFaceStart: '', // 文件上传时的分片文件下标, 作用于断点续传 }) } beforeUpload = (file) => { this.setState({ file, // 把file存起来 }) let reader = new FileReader(); let md5 = ''; reader.onload = (event) => { const spark = new SparkMD5.ArrayBuffer; spark.append(e.target.value); md5 = spark.end(); axios.post('', { md5, id, // 后端需要的 }).then((res) => { const { fileId, start, finish, message } = res.data.data; if(res.data.code !== 200){ message.error(message); } if(finish && finish === 'true'){ this.setState({ file: {}, // 等于true,表示上传完成了 fileplanNumber: 0, // 上传文件进度的百分比 }) message.error(message); return; } // 请求成功后 this.setState({ fileId, interFaceStart: start, // 文件上传时,分片文件下标,为了断点续传 }, () => { this.getSliceFile() // 获取文件切片 }) }) } reader.readArrayBufffer(file); return false; } // 获取文件切片 getSliceFile = async () => { const { search, cataList } = this.props; const { file, fileId, interFaceStart } = this.state; const archiveId = cataList && cataList[cataList.length - 1].archiveId; const fileSize = file.size; // 文件的大小 const piece = 1024 *1024 * 25; // 每片25M let start = 0; // 每次上传开始字节 let index = 1; let end = start + piece; // 每次上传的结尾字节 const chunksList = []; while(start < fileSize){ const current = Math.min(end, fileSize) // 两者中取最小的 const blob = file.slice.call(file, start, current); // 计算分片文件的MD5 let sliceFileMD5 = ''; sliceFileMD5 = await this.getSliceFileMD5(blob ); // 拼接分片信息数据 chunksList.push({ file: blod, index, sliceFileMD5, }); start = current; end = start + piece; index += 1; } // 检验分片数量,开始上传 if (chunksList && chunksList.length) { const chunks = chunksList.slice(interFaceStart); // 分片上传的结果 let resultList = 0; // 循环分片数据 for(const item of chunks){ // 调用接口上传分片内容 const resultFile = await this.uploadSliceFile(item, chunks); //记录上传结果 resultList += 1; // 一次失败,结束后续上传 if(!resultFile){ break; } } // 检验分片数量,分片上传结果数量,全部上传完成,调用合并接口 if(resultList === chunks.length){ const { fileList } = this.state; axios.post('', { fileId, fileName: file.name, businessId: archiveId, businessType: 'archive', }).then((res) => { if(res.data.code !== 200){ message.error(res.data.message) } message.success('上传成功!') // 调接口,刷新页面 axios.post('', { pageNum: 1, pageSize: 10, archiveId, orderBy: '', sort: '', }).then(res => { if(res.code !== 200){ message.error(res.message) }; }) this.setState({ file: {}, fileId: '', fileUploadState: null, fileplanNumber: 0, fileList, interFaceStart: 0, }); }) } else { this.setState({ fileUploadState: fail, }); } } } // 计算分片文件的MD5 getSliceFileMD5 = (blob) => { return new Promise((resolve, reject) => { const sliceFileReader = new FileReader(); let sliceFileMD5 = ''; sliceFileReader.onerror = reject; sliceFileReader.onload = (event) => { const spark = new SparkMD5.ArrayBuffer(); spark.append(event.target.result) sliceFileMD5 = spark.end(); // 返回分片MD5 resolve(sliceFileMD5); } sliceFileReader.readAsArrayBuffer(blob); }) } // 上传分片文件 uploadSliceFile = (fileMap, chunks) => { return new Promise((resolve, reject) => { const { sliceFileMD5, file, index } = fileMap; const fileBlob = new File([file], 'AAA.exe', { type: 'application/x-msdownload' }) const { fileId } = this.state; const formData = new FormData(); formData.append('fileId', fileId); formData.append('MD5', sliceFileMD5); formData.append('partSequence', index); formData.append('fileBlob', fileBlob); axios.post('', { formData, headers: { 'Content-Type': 'multipart/form-data', } }).then(res => { if(res.data.code !== 200){ message.error(res.data.message) return false; } const fileplanNumber = (index / chunks.length) * 100; this.setState({ fileplanNumber, }); resolve(true); }) }) } }
部分代码2:
原文地址:https://blog.csdn.net/qq_47305413/article/details/134466562
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_2934.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。