vue eggjs 文件分片上传

文件大小过大的时候可以对文件进行分片上传
相当于如果10M的文件,可以把每个文件分成1M的大小上传,然后上传完后再进行合并
file.vue

<template>
  <input type="file" id="fileBtn" />
  <input type="button" value="上传" @click="upload" />
  {{ btnFile }}
</template>

<script lang="ts" setup>
import { simpleUpload, sliceUpload, merge } from '@/services/upload';

const chunkSize = 3;
const multipleSize = 1;

// 上传
const upload = (/* index = 0 */) => {
  console.log('upload');
  const btnFile: any = document.querySelector('#fileBtn');
  const file = btnFile?.files[0];
  isMutiple(file);
};

// 是否需要分片
const isMutiple = async (file: any, index = 0) => {
  const { name, size } = file;
  const M = Math.ceil(size / 1024 / 1024);
  // 判断是否需要分片
  if (M < multipleSize) {
    directUpload({ file, name });
  } else {
    // 思路: 将大文件切割成 一片片的小文件
    // 切割起始值,例如10MB得文件分成3MB
    const [fname, fext] = name.split('.');
    let start = index * chunkSize;
    // 初始值大于文件大小 直接返回
    while (start < M) {
      const blob = file.slice(MSize(start), MSize(start + chunkSize));
      const blobName = `${fname}.${index}.${fext}`;
      const formData = handleFormData({ file: blob, name: blobName });
      // 发起请求 上传分片
      await sliceUpload(formData);
      start = start + chunkSize;
      index = index + 1;
    }
    merge({
      name,
    });
  }
};

const MSize = (num: number) => num * 1024 * 1024;

// 直接上传
const directUpload = ({ file, name }: { file: any; name: any }) => {
  const formData = handleFormData({ file, name });
  // 发起请求
  simpleUpload(formData);
};

// 分片上传
const handleFormData = ({ file, name }: { file: any; name: any }) => {
  const blobFile = new File([file], name);
  const formData = new FormData();
  formData.append('file', blobFile);
  return formData;
};
</script>

eggjs服务器端代码

"use strict";

const { Controller } = require("egg");
const path = require("path");

class HomeController extends Controller {
    async sliceUpload() {
        const { ctx } = this;
        console.log(ctx.request);
        // 1 获取上传的文件
        const file = ctx.request.files[0];
        // 2 获取真实的文件名
        const fileNameArr = file.filename.split(".");
        // 3 文件上传路径
        const UPLOAD_DIR = path.resolve(__dirname, "public/upload");
        // 4 文件对应的文件夹
        const chunkDir = `${UPLOAD_DIR}/${fileNameArr[0]}`;
        // 5 判断文件夹是否存在 不存在则新建一个
        if (!fse.existsSync(chunkDir)) {
            await fse.mkdir(chunkDir);
        }
        // 6 分片的路径
        const dPath = path.join(chunkDir, fileNameArr[1]);
        // 7 临时文件移动到当前文件
        await fse.move(file.filepath, dPath, { overwrite: true });
        ctx.body = {
            sliceKey: fileNameArr[1],
            msg: "单片上传成功",
        };
    }

    async merge() {
        const { ctx } = this;
        // 1. 文件上传路径
        const UPLOAD_DIR = path.resolve(__dirname, "public/upload");
        // 2. 拿到文件名
        const { name } = ctx.request.body;
        // 3. 文件路径
        const chunkDir = `${UPLOAD_DIR}/${name.split(".")[0]}`;
        // 4. 读取文件列表
        const chunks = await fse.readdir(chunkDir);
        chunks
            .sort((a, b) => a - b)
            .map((chunkPath) => {
                fse.appendFileSync(
                    path.join(UPLOAD_DIR, name),
                    fse.readFileSync(`${chunkDir}/${chunkPath}`)
                );
            });
        fse.removeSync(chunkDir);
        ctx.body = "合成成功";
    }

    async simpleUpload() {
        const { ctx } = this;
        console.log("request", ctx.request);
        console.log(ctx.request.files);
        if (!ctx.request.files) {
            ctx.body = "文件为空";
            return;
        }
        const file = ctx.request.files[0];
        const UPLOAD_DIR = path.resolve(__dirname, "public/upload");
        const dPath = path.join(UPLOAD_DIR, file.filename);
        await fse.move(file.filepath, dPath, { overwrite: true });
        ctx.body = "文件上传成功";
    }
}

module.exports = HomeController;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值