做了大文件分块上传才知道有多烦

//用到的模块
const fs = require('fs');
const multer = require('multer');
const path = require('path');

直接上接口代码

    router.post('/chunks', chunks_upload.single('file'), async (req, res) => {
        // console.log(req.file);
        // 检查temp目录是否存在  如果不存在就创建
        if (!fs.existsSync(tempDir)) fs.mkdirSync(tempDir, { recursive: true });
        // 异常捕获
        try {
            // 获取文件信息
            const chunkIndex = req.body.index; // 当前为第几块
            const chunkCount = req.body.count; // 总共有几块
            const filename = req.body.filename; // 当前文件的文件名
            console.log(req.files);
            // 创建一个唯一的临时文件名
            const temp_filename = Date.now().toString();
            // 取出文件名不包含.扩展名
            let name = filename.split('.')[0];
            // 根据filename创建一个以temp_filename命名的临时文件夹路径
            const temp_dir = path.join(tempDir, name);
            // 判断文件夹是否存在 如果不存在就创建
            if (!fs.existsSync(temp_dir)) fs.mkdirSync(temp_dir, { recursive: true });
            const tempFilePath = path.join(temp_dir, name + '_' + chunkIndex);// 临时文件路径
            // 使用文件流处理文件上传
            const readStream = fs.createReadStream(req.file.path);// 创建可读流
            const writeStream = fs.createWriteStream(tempFilePath);// 创建可写流
            // 监听可读流完成事件
            readStream.on('end', async () => {
                // 关闭写入流
                writeStream.end();
                // 判断上传的文件是否为最后一块
                if (chunkIndex == chunkCount - 1) {
                    // 如果是最后一块 就将所有的文件块合并成一个文件
                    // 创建一个以temp_filename命名的文件路径 用来保存最终的文件
                    const targetFilePath = path.join(__dirname, '../uploads/chunks', temp_filename, filename);
                    // 判断targetFilePath文件夹是否存在 如果不存在就创建
                    if (!fs.existsSync(path.dirname(targetFilePath))) fs.mkdirSync(path.dirname(targetFilePath), { recursive: true });
                    // 创建一个写入流 用来写入最终的文件
                    const videoWriteStream = fs.createWriteStream(targetFilePath, { flags: 'a' });
                    // 根据总块数合并文件
                    for (let i = 0; i < chunkCount; i++) {
                        // 构建临时文件路径
                        const chunkPath = path.join(temp_dir, name + '_' + i);
                        // 读取分块的文件内容
                        // 文件流方式 解决内存占用过大
                        // 创建可读流
                        const readFlow = fs.createReadStream(chunkPath);
                        readFlow.pipe(videoWriteStream, { end: false }); // 使用pipe来逐块写入
                       //这里必须要用new Promise((resolve, reject) 不然会无法正确监听事件
                        await new Promise((resolve, reject) => {
                            readFlow.on('end', () => {
                                console.log('读取流结束');
                                // 删除临时文件
                                fs.unlinkSync(chunkPath);
                                resolve();
                            })
                        })
                        // 将读取到的块数据写入到最终的文件中
                        // 全部读入到内存的方式
                        // const chunkData = fs.readFileSync(chunkPath);
                        // // 将读取到的块数据写入到最终的文件中
                        // videoWriteStream.write(chunkData);
                        // 全部读入到内存的方式结束
                        // fs.unlinkSync(chunkPath);
                    }
                    // 关闭写入流
                    console.log('关闭写入流');
                    videoWriteStream.end();
                    // 删除临时文件夹
                    // fs.rmdirSync(temp_dir);
                    fs.rm(path.join(tempDir, filename), { recursive: true }, (err) => {
                        if (err) {
                            console.log('文件删除失败');
                            console.error(err);
                        } else {
                            console.log('文件删除成功');
                        }
                    });

                    fs.rm(path.join(temp_dir), { recursive: true }, (err) => {
                        if (err) {
                            console.log('文件夹删除失败');
                            console.error(err);
                        } else {
                            console.log('文件夹删除成功');
                        }
                    });
                    // 返回上传成功的信息
                     res.send({
                         code: 200,
                         msg: '上传成功',
                         url: `http://localhost:3000/uploads/chunks/${temp_filename}/${filename}`
                    })
                } else {
                    // 如果不是最后一块 就继续上传
                    res.send({
                        code: 200,
                        msg: '数据块上传成功'
                    })
                }
            });
            // 将可读流的内容写入到写入流
            readStream.pipe(writeStream);// 管道流
        } catch (err) {
            console.log(err);
            res.status(500).send({
                code: 500,
                msg: '上传失败'
            })
        }
    })
Last modification:August 27, 2023
反正也没人会打赏