前端使用 spark-md5 实现大文件切片上传

需要计算文件MD5和、分片MD5:

封装公共方法代码如下:

javascript 复制代码
import SparkMD5 from "spark-md5"

/**
 * 计算文件MD5
 * @param file
 * @returns
 */
export function calculateFileMD5(file) {
  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.onload = function (e) {
      const spark = new SparkMD5.ArrayBuffer();
      spark.append(e.target.result);
      resolve(spark.end());
    };
    reader.readAsArrayBuffer(file);
  })
}

/**
 * 计算分片MD5
 * @param chunk 当前切切片
 * @returns
 */
export function calculateChunkMD5(chunk) {
  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.onload = function (e) {
      const spark = new SparkMD5.ArrayBuffer();
      spark.append(e.target.result);
      resolve(spark.end());
    };
    reader.readAsArrayBuffer(chunk);
  })
}

在上传页面调用:

javascript 复制代码
<template>
  <form id="uploadForm">
    <div class="fileBox">
      <span class="fileLabel">文件:&nbsp; </span>
      <input type="file" id="file" name="file">
    </div>
    <el-progress id="progressBar" :percentage="progress" style="width: 335px;"></el-progress>
    <button type="submit">提交</button>
  </form>
</template>

<script setup>
import { calculateFileMD5, calculateChunkMD5 } from './calculateMd5'
import { ElMessage, ElMessageBox } from 'element-plus'
import axios from 'axios'
import { getToken } from "@/utils/auth";
const emit = defineEmits(['send-upload'])
const uploadChunkUrl = ref(import.meta.env.VITE_APP_BASE_API + "/dbms/file/chunk"); //上传接口
const mergeUrl = ref(import.meta.env.VITE_APP_BASE_API + "/dbms/file/merge"); //合并接口

const file = ref(null)
const progress = ref(0)

async function uploadFile(file) {
  const chunkSize = 5 * 1024 * 1024; // 5MB每片
  const totalChunks = Math.ceil(file.size / chunkSize);
  const fileMd5 = await calculateFileMD5(file); // 计算整个文件的MD5

  for (let i = 0; i < totalChunks; i++) {
    const start = i * chunkSize;
    const end = Math.min(file.size, start + chunkSize);
    const chunk = file.slice(start, end);
    const chunkMd5 = await calculateChunkMD5(chunk); // 计算当前分片的MD5
    progress.value = Math.round((i / totalChunks) * 100) // 计算上传进度

    const formData = new FormData();
    
    formData.append('file', chunk);
    formData.append('chunkNumber', i + 1);
    formData.append('totalChunks', totalChunks);
    formData.append('fileMd5', fileMd5);
    formData.append('chunkMd5', chunkMd5);
    formData.append('fileName', file.name);

    await axios.post(uploadChunkUrl.value, formData, {
      headers: { 'Content-Type': 'multipart/form-data', 'Authorization': 'Bearer ' + getToken() }
    });
  }

  // 所有分片上传完成后,通知后端合并
  const res = await axios.post(mergeUrl.value, {
    fileMd5: fileMd5,
    fileName: file.name,
    totalChunks: totalChunks
  });
  // console.log(res)
  if (res.status == 200) {
    progress.value = 100
    ElMessage.success('文件上传成功!')
    // 上传成功 通知父组件关闭弹窗,清空下拉表单,更新列表数据
    emit('send-upload')
  }
}

onMounted(async () => {
  /**触发上传**/
  document.getElementById("uploadForm").onsubmit = async function (event) {
    event.preventDefault();
    
    const fileInput = document.getElementById("file");
    file.value = fileInput.files[0];
    if (!file.value) {
      ElMessage.warning("请选择文件!")
      return;
    }
    uploadFile(file.value)
  }
})
</script>
相关推荐
人工智能训练师13 分钟前
Ubuntu22.04如何安装新版本的Node.js和npm
linux·运维·前端·人工智能·ubuntu·npm·node.js
Seveny0718 分钟前
pnpm相对于npm,yarn的优势
前端·npm·node.js
yddddddy1 小时前
css的基本知识
前端·css
大数据CLUB1 小时前
基于spark的澳洲光伏发电站选址预测
大数据·hadoop·分布式·数据分析·spark·数据开发
昔人'1 小时前
css `lh`单位
前端·css
ratbag6720132 小时前
当环保遇上大数据:生态环境大数据技术专业的课程侧重哪些领域?
大数据
Nan_Shu_6143 小时前
Web前端面试题(2)
前端
知识分享小能手3 小时前
React学习教程,从入门到精通,React 组件核心语法知识点详解(类组件体系)(19)
前端·javascript·vue.js·学习·react.js·react·anti-design-vue
计算机编程小央姐3 小时前
跟上大数据时代步伐:食物营养数据可视化分析系统技术前沿解析
大数据·hadoop·信息可视化·spark·django·课程设计·食物
蚂蚁RichLab前端团队4 小时前
🚀🚀🚀 RichLab - 花呗前端团队招贤纳士 - 【转岗/内推/社招】
前端·javascript·人工智能