首页 > 其他分享 >【vue3组件】【大文件上传】【断点续传】支持文件分块上传,能够在上传过程中暂停、继续上传的组件

【vue3组件】【大文件上传】【断点续传】支持文件分块上传,能够在上传过程中暂停、继续上传的组件

时间:2025-01-22 15:28:54浏览次数:3  
标签:文件 const 分块 value file 组件 上传

一、概述

本示例实现了一个基于 Vue3 和 TypeScript 的断点上传功能。该功能支持文件分块上传,能够在上传过程中暂停、继续上传,并且支持检测已经上传的分块,避免重复上传,提升上传效率。以下是关键的技术点与实现流程:

  • 文件分块:将大文件分成多个小块,每块的大小是固定的(例如 5MB)。
  • 上传进度:通过进度条显示文件上传的进度。
  • 断点续传:支持暂停和继续上传,避免上传过程中断导致的文件重新上传。
  • 文件哈希:通过计算文件的哈希值来唯一标识文件,并检查文件是否已经上传完成。

二、实现步骤

(一)定义状态变量

通过 ref 定义一些响应式状态变量来管理文件、进度、上传状态等信息:

const file = ref<File | null>(null);
const fileHash = ref<string>('');
const chunkSize = 5 * 1024 * 1024; // 每个分块大小(5MB)
const uploadedChunks = ref<number[]>([]); // 已上传的分块索引
const progress = ref<number>(0); // 上传进度
const paused = ref<boolean>(false); // 上传是否暂停
const uploading = ref<boolean>(false); // 是否正在上传

(二)监听文件选择并计算哈希

当用户选择文件后,计算该文件的 SHA-256 哈希值,哈希值用来判断文件是否已经上传过。

const onFileChange = (event: Event) => {
  const target = event.target as HTMLInputElement;
  file.value = target.files?.[0] || null;
  if (file.value) {
    calculateFileHash();
  }
};

const calculateFileHash = async () => {
  if (!file.value) return;
  const buffer = await file.value.arrayBuffer();
  const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
  fileHash.value = [...new Uint8Array(hashBuffer)]
    .map((b) => b.toString(16).padStart(2, '0'))
    .join('');
  await checkUploadedChunks();
};

(三)检查已上传的分块

调用后端接口检查文件的部分分块是否已经上传,以避免重复上传。

const checkUploadedChunks = async () => {
  try {
    const response = await axios.get(getUploadedChunksApi.value, {
      params: { fileHash: fileHash.value },
    });

    if (response.data.uploadedChunks === 'completed') {
      alert('文件已上传完成!');
      progress.value = 100; // 设置进度为 100%
      return true; // 文件已完成上传
    }

    uploadedChunks.value = response.data.uploadedChunks || [];
    return false; // 文件未完成上传
  } catch (error) {
    console.error('Error checking uploaded chunks:', error);
    return false;
  }
};

(四)开始上传

分块上传文件。上传时检查哪些分块已经上传,跳过已上传的分块。如果上传中出现错误,可以暂停上传。

const startUpload = async () => {
  if (!file.value) return;
  paused.value = false;
  uploading.value = true;

  const isCompleted = await checkUploadedChunks();
  if (isCompleted) {
    uploading.value = false;
    return;
  }

  const totalChunks = Math.ceil(file.value.size / chunkSize);
  for (let i = 0; i < totalChunks; i++) {
    if (paused.value) break;
    if (uploadedChunks.value.includes(i)) {
      progress.value = ((i + 1) / totalChunks) * 100;
      continue;
    }
    const chunk = file.value.slice(i * chunkSize, (i + 1) * chunkSize);
    const formData = new FormData();
    formData.append('file', chunk);
    formData.append('chunkIndex', i.toString());
    formData.append('fileHash', fileHash.value);
    formData.append('totalChunks', totalChunks.toString());

    try {
      await axios.post(uploadChunkApi.value, formData);
      uploadedChunks.value.push(i);
      progress.value = ((i + 1) / totalChunks) * 100;
    } catch (error) {
      console.error('Error uploading chunk:', error);
      paused.value = true;
      break;
    }
  }

  if (!paused.value && progress.value === 100) {
    completeUpload();
  }
  uploading.value = false;
};

(五)暂停与继续上传

提供暂停与继续上传的功能,通过控制 paused 变量来实现。

const pauseUpload = () => {
  paused.value = true;
  uploading.value = false;
};

const resumeUpload = () => {
  paused.value = false;
  startUpload();
};

(六)合并分块

所有分块上传完成后,通过后端接口提交合并请求,合并文件。

const completeUpload = async () => {
  try {
    await axios.post(completeUploadApi.value, {
      fileHash: fileHash.value,
      fileExtension: file.value?.name.split('.').pop(),
      fileName: file.value?.name,
    });
    alert('文件上传完成!');
  } catch (error) {
    console.error('Error completing upload:', error);
  }
};

三、模板部分

<template>
  <div class="upload">
    <h2>断点上传</h2>
    <input type="file" @change="onFileChange" />
    <div v-if="file">
      <p>文件名: {{ file.name }}</p>
      <p>文件大小: {{ (file.size / 1024 / 1024).toFixed(2) }} MB</p>
      <progress :value="progress" max="100"></progress>
      <div class="actions">
        <button @click="startUpload" :disabled="uploading">开始上传</button>
        <button @click="pauseUpload" :disabled="!uploading">暂停上传</button>
        <button @click="resumeUpload" :disabled="uploading || !paused">
          继续上传
        </button>
      </div>
    </div>
  </div>
</template>

四、样式部分

<style scoped>
.upload {
  width: 400px;
  margin: 20px auto;
}

.actions {
  margin-top: 10px;
}

button {
  margin-right: 10px;
}

progress {
  width: 100%;
  height: 20px;
  margin-top: 10px;
}
</style>

五、总结

通过以上的实现,我们可以完成一个支持断点续传和分块上传的功能。该方案不仅提升了大文件上传的效率,还避免了上传过程中断的影响。通过 Vue3 与 TypeScript 的结合,实现了清晰的状态管理和组件化的文件上传逻辑,便于后续的维护和扩展。

该功能组件已在github开源(对应后端也已开源)在apps\web-ele\src\views\test\test5\index.vue

标签:文件,const,分块,value,file,组件,上传
From: https://blog.csdn.net/qq_59344127/article/details/145304338

相关文章

  • 【Django DRF Apps】【文件上传】【断点上传】从零搭建一个普通文件上传,断点续传的App
    DjangoDRF应用搭建文档:普通文件上传与大文件断点上传本文档将指导你从零搭建一个支持普通文件上传和大文件断点上传功能的DjangoDRF应用。我们将通过两部分内容进行说明:普通文件上传功能和分片上传功能。功能点说明普通文件上传:处理普通文件上传,支持根据文件内容......
  • 如何在Python中高效地读写大型文件?
    大家好,我是V哥。上一篇给大家介绍如何使用Python进行文件读写操作的方法,问题来了,如何读写的是大型文件,有没有什么方法来提高效率呢,不要捉急,这一篇来聊聊如何在Python中高效地读写大型文件。以下是在Python中高效读写大型文件的一些方法:一、逐行读取大型文件:defread_larg......
  • linux文件IO:select
    select电平触发#include<sys/time.h>#include<sys/types.h>#include<unistd.h>intselect(intn,fd_set*readfds,fd_set*writefds,fd_set*exceptfds,structtimeval*timeout);在指定的文件描述符准备好I/O之前或超过一定时间限制,select调用会被阻塞readfds文件描......
  • 如何在 Linux 服务器上设置 FTP 文件传输协议
    第一步:安装vsftpd要在Linux上设置FTP服务器,首先需要确保已安装vsftpd。对于Ubuntu/Debian系统:sudoaptupdatesudoaptinstallvsftpd-y对于CentOS/RHEL系统:sudoyuminstallvsftpd-y第二步:配置vsftpd配置vsftpd以允许基本的FTP连接并设置用户限......
  • 如何用vscode打开obj、glb文件,查看3D文件
    方案1:安装插件3DViewerforVSCode,安装完可以查看obj但是不懂为啥是白色的  glTFTools,安装完可以查看gltf启动位置在右上角:白色小山的图标 这个效果不错,看起来比较舒服。 但是gltf从哪里来呢?首先我们有一个glb文件,右键它,点击倒数第二行的“glTF:importfromG......
  • 小程序中 button 和 image 组件的基本用法
    目录小程序中button和image组件的基本用法一、button组件(一)基本属性(二)事件绑定二、image组件(一)基本属性(二)图片加载优化在小程序开发中,button和image组件是常用的元素,它们能为用户界面增添交互性和丰富的视觉效果。以下将详细介绍这两个组件的基本用法,并附......
  • Debian解压zip文件时中文文件名称乱码
    使用unzip解压文件,如下:merit@tt-raspberrypi5:/home/pi$unzipmakerobo_code.zipArchive:makerobo_code.zipcreating:makerobo_code/creating:makerobo_code/.ipynb_checkpoints/inflating:makerobo_code/.ipynb_checkpoints/1.-▒+▒LED-▒▒▒-checkpoint.i......
  • python 读取word、pdf文件内容
    importdocx2txtimportfitzimportdocxfromdocx.oxmlimportparse_xmldefget_doc_content(filepath):"""获取word文本内容"""try:doc=docx.Document(filepath)content=[]forelementindoc.elem......
  • Csharp上传大文件到服务器指定文件夹问题
    功能:大文件上传下载,断点续传,文件夹上传下载,加密传输,加密存储,云对象存储要求:免费,开源,技术支持前端:vue2,vue3,react,vue-cli,html,jquery后端:asp.net,vb.net,.netcore,.netmvc,.netwebform平台:Windows,macOS,Linux,Ubuntu,RedHat,CentOS,中标麒麟,银河麒麟,统信UOS,信......
  • VUE分片上传大型视频文件到服务器解决方案
    要求:免费,开源,技术支持技术:百度webuploader,分块,切片,断点续传,秒传,MD5验证,纯JS实现,支持第三方软件集成前端:vue2,vue3,vue-cli,html5,webuploader后端:asp.net,.netmvc,.netcore,asp,jsp,java,springboot,php,数据库:MySQL,Oracle,SQLServer,达梦,人大金仓,国产数据库平......