大文件分片上传

60 阅读1分钟
async function handleUpload(file:any){
  const chunkSize = 5 * 1024 * 1024; // 每个切片的大小,这里设置为5MB
  // 计算文件的总切片数
  const totalChunks = Math.ceil(file.file.size / chunkSize);
  // 创建一个存储切片MD5的数组
  const chunkMD5s: any[] = [];
  const chunks: any[] = [];
  // 逐个切片计算MD5
  let currentChunk = 0;
  const fileReader = new FileReader();
  fileReader.onload =  async e => {
    const spark = new SparkMD5.ArrayBuffer();
    spark.append(e.target!.result as ArrayBuffer);
    chunkMD5s.push(spark.end());

    currentChunk++;
    if (currentChunk < totalChunks) {
      loadNextChunk(chunks);
    } else {
      // 所有切片的MD5计算完成,可以进行上传或其他操作
      const assembleMd5 = chunkMD5s[chunkMD5s.length - 1]; //总md5
      const parts: { partMd5: any; partNumber: number; partSize: any; }[] = [];
      chunkMD5s.forEach((item, index) => {
        parts.push({
          partMd5: item,
          partNumber: index + 1,
          partSize: chunks[index].size
        });
      });
      let params = {
        objectMd5: assembleMd5,
        objectName: file.file.name,
        fileName: file.file.name,
        fileSuffix: file.file.name.split('.')[1],
        parts: parts
      };
      // 定义一个变量放总计的切片  定义一个变量放上传完成的切片   this.plan = this.currentProgress
      let totalParts = parts.length,
        alParts = currentProgress.value ? currentProgress.value - 1 : 0;
      try {
        const res = await "你的上传接口"(params) as any
        if(res.code == '200' && res.data != null){
          if (res.data[0].alreadyUpload) {
            // 说明文件已经上传过
            return;
          }
          let completeParams = {
            fileName: file.file.name,
            objectMd5: assembleMd5,
            uploadId: res.data[0].uploadId,
            objectName: file.file.name,
            fileSuffix: file.file.name.split('.')[1]
          };
          // 查找一下文件的状态status是不是完成了都
          let hasEven = res.data.some((e: { status: number; }) => {
            return e.status === 0;
          });
          res.data.forEach((item: { status: number; })=>{
            if(item.status == 1){
              currentProgress.value++
            }
            if(hasEven && item.status == 0){
              uploadChunk(item, completeParams);
            }
          })
        }
      } catch (error) {
        console.log('error', error);
      }
      async function uploadChunk(data:any, completeParams:any){
        try {
          const response = await axios.put(data.presignedUrl, chunks[data.partNumber - 1]);
          await updateProgressAndComplete(data, completeParams);
          return response.data;
        } catch (error) {
          console.log(error)
          throw error;
        }
      };
      // 更新进度及完成
      async function updateProgressAndComplete(data:any, completeParams:any){
        try {
          await _api.partStatusUpdate({ partInfoId: data.id });
          currentProgress.value++;
          // 成功一个减少一个
          alParts = currentProgress.value;
          if (currentProgress.value == data.partTotal) {
            currentProgress.value = 0;
            const completeRes = await _api.complete(completeParams) as any;
            if (completeRes.code == '200') {
              downloadBtnShow.value = true;
              emit('getField', { fileId: completeRes.data });
            }
          }
        } catch (error) {
          console.error(error);
        }
      }
    }
  };

  const loadNextChunk = (chunks: any[]) => {
    const start = currentChunk * chunkSize;
    const end = Math.min(start + chunkSize, file.file.size);
    const chunk = file.file.slice(start, end);
    chunks.push(chunk);
    fileReader.readAsArrayBuffer(chunk);
  };
  loadNextChunk(chunks);
}