单个大文件分片上传

后台管理系统中,牵扯到安装包管理。超级大的apk包和ipa包需要进行分片上传,上传前需要进行文件是否重复校验,文件md5计算等操作。

1. 文件分片

因为一般服务器一次可上传的文件大小有限。可以跟接口端讨论确认可传的分片大小。将几个G的文件按照固定的大小分成若干片。

js 复制代码
 // 文件分片
export const SIZE = 10 * 1024 * 1024; // 分片大小 10M
export const createFileChunk = (file, size=SIZE) => {
   const fileChunkList = [];
   let cur = 0;
   while(cur < file.size) {
     fileChunkList.push({
       file: file.slice(cur, cur + size)
     });
     cur += size;
   }
   return fileChunkList;
 };

2. 计算文件的MD5

选择sparkMD5的三方库进行hash值的计算。单个文件使用worker好似不大必要。但是后续如果扩展到文件夹上传,文件夹中如果包含非常多的大小文件,那么worker就会变得非常必要了。

js 复制代码
import WorkerPath from "./1.worker.js";
 // 计算大文件HASH
export const calculate = (fileChunkList) => {
   return new Promise((resolve) => {
     const worker = new WorkerPath();
     worker.postMessage({ fileChunkList });
     worker.onmessage = (e) => {
       const { hash } = e.data;
       if (hash) {
         resolve(hash);
       }
     };
   });
 };

然而解析worker.js需要单独的loader来处理。

首先,需要安装 npm install worker-loader -D

其次需要在webpack中进行loader的配置

js 复制代码
// 在rules中配置
      {
        // 匹配 *.worker.js
        test: /\.worker\.js$/,
        use: {
          loader: "worker-loader",
        },
      }

然后,在worker中进行md5的计算

js 复制代码
// 1.worker.js
importScripts("../static/spark-md5.min.js"); //引入本地的三方库

onmessage = function(event) {
    const { fileChunkList } = event.data;

    const spark = new SparkMD5.ArrayBuffer();
    let count = 0;
    const loadNext = (index) => {
        const reader  = new FileReader();
        reader.readAsArrayBuffer(fileChunkList[index].file);
        reader.onload = (e) => {
            count++;
            spark.append(e.target.result);
            if (count === fileChunkList.length) {
                this.postMessage({
                    hash: spark.end()
                });
                this.close();
            }
            loadNext(count);
        };
    };

    loadNext(0);
};

3. 文件检查

调用接口的check方法检查该文件是否已经上传过。如果上传过则不再上传。如果未上传过则开始上传。

4. 文件上传

根据1,2获取到的分片和md5值,进行上传。所有的分片同时上传,浏览器自动限制6-8个请求。剩余的请求会pending。

js 复制代码
    // 所有的分片同时上传,浏览器自动限制6-8个请求
    const promises = fileChunkList.forEach(({file: chunkFile}, index) =>{
      const passedData = {
         chunk: index + 1,
         file: chunkFile,
         name:formData.filename,
         md5: hash,
         totalChunk: fileChunkList.length,
         position: index * SIZE,
         totalSize: formData.file.size,
         chunked: true,
      };
      // uploadPackFile是自己封装的上传方法
      const promiseTemp = uploadPackFile("/upload", passedData,function() {
        progressRef.current = progressRef.current + 1; // 记录上传进度
      });
    });
    // 等待所有的请求结束
    Promise.all(promises).then(result => {
       // 进行上传结束后的一些操作
    })

文件上传进度的加载状态

文件上传各个阶段都是需要等待的过程,比如"上传中..."。后面的三个点可以动态展示。

代码如下:

html 复制代码
<span>上传中<span className='dot'>...</span></span>

样式如下:

css 复制代码
span.dot {
  display: inline-block;
  height: 1em;
  line-height: 1;
  text-align: left;
  vertical-align: -.25em;
  overflow: hidden;
  text-indent: 0;
}
span.dot::before {
  display: block;
  content: '...\A..\A.';
  white-space: pre-wrap;
  animation: dot 1s infinite step-start both;
}
@keyframes dot {
  33% { transform: translateY(-2em); }
  66% { transform: translateY(-1em); }
}
相关推荐
Baklib梅梅6 小时前
探码科技再获“专精特新”认定:Baklib引领AI内容管理新方向
前端·ruby on rails·前端框架·ruby
南方以南_6 小时前
Chrome开发者工具
前端·chrome
YiHanXii6 小时前
this 输出题
前端·javascript·1024程序员节
楊无好6 小时前
React中ref
前端·react.js
程琬清君6 小时前
vue3 confirm倒计时
前端·1024程序员节
歪歪1007 小时前
在C#中详细介绍一下Visual Studio中如何使用数据可视化工具
开发语言·前端·c#·visual studio code·visual studio·1024程序员节
唔667 小时前
flutter实现web端实现效果
前端·flutter
csj507 小时前
前端基础之《React(2)—webpack简介-使用Babel》
前端·react
刘新明19898 小时前
算法还原案例4-OLLVM_MD5
开发语言·前端·javascript·1024程序员节
言德斐9 小时前
Python Web框架深度对比:Django vs Flask vs FastAPI(含优缺点与选型策略)
前端·python·django