Vue小玩意儿:vue3+express.js实现大文件分片上传

vue3:

javascript 复制代码
<template>
  <div>
    <h1>大文件分片上传</h1>
    <input type="file" @change="onFileChange"/>
    <div v-if="progress > 0">
      上传进度: {{ progress }}%
    </div>
  </div>
</template>

<script setup>
import axios from 'axios'
import {ref} from 'vue'

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

const onFileChange = (event) => {
  file.value = event.target.files[0]
  if (file.value) {
    uploadFile()
  }
}

const uploadFile = async () => {
  progress.value = 0

  const chunkSize = 1 * 1024 * 1024 // 1MB 分片
  const totalChunks = Math.ceil(file.value.size / chunkSize)

  for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
    const start = chunkIndex * chunkSize
    const end = Math.min(start + chunkSize, file.value.size)
    const chunk = file.value.slice(start, end)

    const formData = new FormData()
    formData.append('file', chunk)
    formData.append('chunkIndex', chunkIndex)
    formData.append('totalChunks', totalChunks)
    formData.append('fileName', file.value.name)

    await axios.post('http://localhost:3000/upload', formData, {
      headers: {
        'Content-Type': 'multipart/form-data'
      }
    })

    progress.value = Math.round(((chunkIndex + 1) / totalChunks) * 100)
  }

  // await axios.post('http://localhost:3000/merge', {
  //   filename: this.selectedFile.name,
  //   totalChunks,
  // });

  alert('文件上传成功!');
}
</script>

express.js:

javascript 复制代码
const express = require('express');
const multer = require('multer');
const fs = require('fs-extra');
const path = require('path');
const cors = require('cors');

const app = express();
const PORT = 3000;

app.use(cors());
app.use(express.json());

const upload = multer({dest: 'uploads/'});

app.post('/upload', upload.single('file'), async (req, res) => {
    const {originalname} = req.file;
    const {chunkIndex, totalChunks, fileName} = req.body;
    const chunkDir = path.join(__dirname, 'uploads', fileName.split('.')[0] + '_' + fileName.split('.')[1]);

    try {
        await fs.ensureDir(chunkDir);
        const chunkPath = path.join(chunkDir, chunkIndex);
        await fs.move(req.file.path, chunkPath);

        if (parseInt(chunkIndex) + 1 == parseInt(totalChunks)) {
            await mergeChunks(chunkDir, fileName);
            res.send({message: `Chunk ${chunkIndex} uploaded.Upload complete.`});
        } else {
            res.send({message: `Chunk ${chunkIndex} uploaded.`});
        }
    } catch (err) {
        console.error(err);
        res.status(500).send({message: 'Upload failed.', error: err.message});
    }
});

async function mergeChunks(chunkDir, fileName) {
    const filePath = path.join(__dirname, 'uploads', fileName);
    const chunkPaths = await fs.readdir(chunkDir);

    chunkPaths.sort((a, b) => parseInt(a) - parseInt(b));

    for (let chunkPath of chunkPaths) {
        const chunkFullPath = path.join(chunkDir, chunkPath);
        await fs.appendFile(filePath, await fs.readFile(chunkFullPath));
    }

    await fs.remove(chunkDir);
}

app.listen(PORT, () => {
    console.log(`Server is running on http://localhost:${PORT}`);
});

后端(Express.js):处理文件上传、分片存储和文件合并。

前端(Vue 3 + Axios):实现文件分片上传,并与后端进行通信。

分片上传:文件被切分为多个小块上传,后端在接收到所有分片后合并为完整的文件。

相关推荐
paopaokaka_luck7 小时前
英语单词学习系统的设计与实现(基于艾宾浩斯遗忘曲线的智能复习机制、语音朗读、多题型测试与错题自动收录、Echarts图形化分析)
vue.js·spring boot·后端·echarts
Momo__12 小时前
Vite 8.1 打包开发模式——10000 组件冷启动 15 倍,"No Bundle Dev" 七年后被自己终结
前端·vue.js·vite
HUMHSX13 小时前
Vue 组件通信核心知识点梳理
javascript·vue.js·ecmascript
妙码生花14 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(二十六):icon 组件封装
前端·vue.js·typescript
李明卫杭州14 小时前
Vue2 & Vue3 中 Router `props` 配置详解:彻底摆脱 `$route` 依赖
前端·vue.js·前端框架
熊猫钓鱼>_>14 小时前
2026 前端的三场底层革命:当 Vue、React Native 和 Three.js 同时去掉中间层
前端·javascript·vue.js·react native·架构·webgl·three.js
自己记录_理解更深刻14 小时前
Computed 聚合依赖+ 竞态处理
vue.js
李明卫杭州16 小时前
Vue3 Suspense 组件详解:从入门到避坑指南
vue.js
gis开发之家20 小时前
vue3组合式函数(Composables)的艺术——将业务逻辑从UI组件中连根拔起
前端·javascript·vue.js·前端框架·vue3·前端工程化·前端架构
uuai20 小时前
vue导出pdf
前端·vue.js·pdf