大文件切片上传

大文件分片上传

代码示例
fs-extra

  • 前端:

    利用 Blob.prototype.slice 方法对大文件进行分片,和数组的slice类似,调用之后可以返回大文件中对应的分片文件。

    这样我们就可以把大文件切分成一个个的小片段,利用http的可并发性,同时上传多个分片,这样从上传一个大文件变成了同时上传多个小文件,大大的减少了上传时间。

    • 分片顺序

    由于http的可并发性,多个文件可以同时上传,这时记录每个分片的顺序是尤为重要的,否则之后合并的时候会出错。

    解决:将传给后端的文件名按照:文件的名称+index+后缀命名

    后端处理:文件的名称作为当前分片的整个文件夹名称,index作为分片的名称

    保证了分片的顺序

    • 何时合并分片

    index * chunkSize : index当前切片的顺序, chunkSize 每片饭店大小 如果这个大小大于当前文件总大小,说明所有分片已经全部上传完成,进行合并分片

<template>
    <div>
        <input type="file" ref="btnFile" />
        <button @click="uploadFile(0)">上传</button>
    </div>
</template>

<script setup>
import { upphoto, uploadSlice, merge } from "@/api/items";
import { ref } from "vue";
const btnFile = ref(null);
const chunkSize = 1024 * 1024;
const uploadFile = (index) => {
    let file = btnFile.value.files[0];
    let fileNameArr = file.name.split(".");
    let fname = fileNameArr[0];
    let fext = fileNameArr[1];
    let start = index * chunkSize;
    if (start > file.size) {
        handlemerge(file.name);
        return;
    }
    let blob = file.slice(start, start + chunkSize);
    let blobName = `${fname}.${index}.${fext}`; // 文件名:文件的名称+index+后缀命名
    let blobFile = new File([blob], blobName);
    let formData = new FormData();
    formData.append("file", blobFile);
    uploadSlice(formData).then((res) => {
        uploadFile(++index);
    });
};
const handlemerge = (name) => {
    merge({ name }).then((res) => {
        console.log(res);
    });
};
</script>
<style lang='scss' scoped>
</style>
  • node端

    利用appendFileSync将分片数据合并,appendFileSync()方法用于将给定数据同步追加到文件中。如果新文件不存在,则会创建一个新文件。

module.exports = (app) => {
    const express = require('express');
    const router = express.Router();
    const multiparty = require('multiparty')
    const fs = require('fs')
    const fse = require('fs-extra')
    const path = require('path')
    const upload_dir = __dirname + '/../../uploadsMultipart/slice'
    router.post('/uploadSlice', (req, res) => {
        const form = new multiparty.Form({ uploadDir: upload_dir })
        form.parse(req)
        form.on('file', async (name, chunk) => {
            console.log(chunk);
            // 存放切片的目录 
            let chunkDir = `${upload_dir}/${chunk.originalFilename.split('.')[0]}`
            // 是否存在 chunkDir 这个目录,不存在就创建一个
            if (!fse.existsSync(chunkDir)) {
                await fse.mkdirs(chunkDir)
            }
            // 原文件名
            let dPath = path.join(chunkDir, chunk.originalFilename.split('.')[1])
            // 移动文件
            await fse.move(chunk.path, dPath, { overwrite: true })
            res.send('文件上传成功')
        })
    })
    router.post('/merge', async (req, res) => {
        let name = req.body.name
        let fname = name.split('.')[0]
        let chunkDir = path.join(upload_dir, fname)
        let chunks = await fse.readdir(chunkDir)
        // 进行排序合并
        chunks.sort((a, b) => a - b).map(chunkPath => {
            fs.appendFileSync(
                path.join(upload_dir, name),
                fs.readFileSync(`${chunkDir}/${chunkPath}`)
            )
        })
        // 删除文件夹
        fse.removeSync(chunkDir)
        res.send({
            msg: '合并成功',
            url: `http://localhost:9000/uploadsMultipart/slice/${name}`
        })
    })
    app.use('/admin/api', router);
    
}
  • uploadsMultipart/slice 文件目录图示

uploadsMultipart/slice 文件目录图示

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值