前端使用 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>
相关推荐
HelloReader几秒前
Qt 项目构建入门CMake 完全指南(三)
前端
zxsz_com_cn5 分钟前
设备预测性维护方案设计的关键要素
大数据·人工智能
唐天下闻化7 分钟前
连锁数字化改造8成翻车?三维避坑实录
大数据
用户908324602737 分钟前
Spring AI + RAG + SSE 实现带搜索来源的智能问答完整方案
前端·后端
GISer_Jing12 分钟前
阿里开源纯前端浏览器自动化 PageAgent,[特殊字符] 浏览器自动化变天啦?
前端·人工智能·自动化·aigc·交互
清风徐来QCQ31 分钟前
js中的模板字符串
开发语言·前端·javascript
成都渲染101云渲染666636 分钟前
Houdini+Blender高效渲染方案(高配算力+全渲染器兼容)
前端·系统架构
SuperEugene1 小时前
Vue3 + Element Plus 表格实战:批量操作、行内编辑、跨页选中逻辑统一|表单与表格规范篇
开发语言·前端·javascript
极梦网络无忧1 小时前
基于 Vite + Vue3 的组件自动注册功能
前端·javascript·vue.js