Node下载阿里OSS存储文件【不知目录结构】

前言:前端传模型ID,后台根据ID去阿里OSS存储下载对应文件(不知文件内部层级结构,且OSS只能单个文件下载),打包成zip字节流形式返回给前端下载。

需求分析:

  • 生成OSS文件关系树
  • Node做文件下载存储
  • 打包返回给前端

一、前期准备

OK! 现在我们做完了需求调研,当然也要确认技术基本架构,因为这个需求是针对模型资源的,后期会继续累加对应需求(上传、拷贝、预览、引用、编辑等),领导要求分模块构建项目,故新构建一个后台项目,如下:

  • dependencies
    • Koa2(body、router、cors) + mysql2(sequelize) + adm-zip + ali-oss
  • devDependencies
    • dotenv + nodemon

image.png

二、完成业务需求

1.生成OSS文件关系树

我们开发是对接的ali-oss开发文档,会调用内置文件操作api,代码中会写明。
代码遵循单一原则

// 获取目录和文件地址
async function getUrl(url, modelId) {
    // modelOSS.listV2, 列举文件层级最深值为100
    return await modelOSS.listV2({
        prefix: url ? url : "models/" + modelId + '/',
        // 设置正斜线(/)为文件夹的分隔符。
        delimiter: "/",
    });
}
// 获取文件夹数组集合 和 文件数组集合
// 思路:
//     判断是否是最后一层,
//     使用递归把每一层的文件夹或文件地址存储到数组
//     运用闭包做数据持久化

async function getPathArr(modelId){
    const prefixesArr = []; // 文件夹数组集合
    const objectsArr = []; // 文件数组集合

    let isFirst = true;

    const resultPaths = async (url) => {
        const resultList = await getUrl(url, modelId); // 获取目录
        if(resultList.prefixes) {
            // 获取文件夹
            resultList.prefixes.forEach(async (subDir) => {
                    prefixesArr.push(subDir);
                    // console.log("SubDir: %s", subDir);
            });
        }

        if(resultList.objects) {
            // 获取文件
            resultList.objects.forEach(async (obj) => {
                    objectsArr.push(obj.name);
                    // console.log("Object: %s", obj.name);
            });
        }

        if(url)	isFirst = false;
    }


    if(isFirst) await resultPaths();

    for(let i = 0; i < prefixesArr.length; i++){
        if(prefixesArr[i].substr(-1) === '/'){
                await resultPaths(prefixesArr[i])
        }
    }

    return {
        prefixesArr,
        objectsArr
    }
}

返回数据如下,每个模型ID返回的对应文件都可能不同

image.png

2.Node做文件下载存储

  • fs中间件不支持逐级创建文件路径,故手写一个公共方法:

    // 通过文件地址,逐级创建文件夹
    function newFolders(folderPath) {
        const arr = folderPath.split('/') // 分割字符串
        let path = ''
        arr.forEach((value, i) => {
            path += value + '/'
            if (!fs.existsSync(path)) {  //判断是否存在该目录
                fs.mkdirSync(path)
            }
        })
    }
    
  • type判断传过来的路径类型(文件或文件夹),分类创建或下载

    // 通过远端模型文件层级生成文件夹,下载文件
    async function downloadModelFile(targeDirList, type){
        try{
            if(type){
                const result = await modelOSS.getStream(targeDirList); // 下载文件
                // 创建文件并且写入
                const writeStream = fs.createWriteStream(`src/examplefile/${targeDirList}`);
                result.stream.pipe(writeStream);
            } else {
                // 查看是否有此目录,如果没有则创建
                if (!fs.existsSync(`src/examplefile/${targeDirList}`)){
                        newFolders(`src/examplefile/${targeDirList}`);
                }
            }
        }catch(e){
            console.log(e)
        }
    }
    
  • 本地与远端文件一致时,打包文件

    async function downFile(targeDirList, type, modelId) {
        // targeDirList => 文件或文件夹远端地址
        // type => 如果传入代表是文件
        // modelId => 模型ID
    
        // 如果是文件夹的话直接创建,是文件的话直接下载
        try {
            for (let i = 0; i < targeDirList.length; i++) {
                downloadModelFile(targeDirList[i], type); // 文件下载
                let loopNum = i + 1;   
                if (loopNum === targeDirList.length) {
                    var zip = new AdmZip();
                    // 压缩文件夹
                    zip.addLocalFolder('src/examplefile/models/' + modelId);
                    zip.writeZip('src/examplefile/models/' + modelId + '.zip');
                }
            }
        } catch (e) {
            console.log(e);
            return e.status;
        }
    }
    

生成如下:
image.png

3.返回给前端

// 抛出模型下载接口
async function exportModel(ctx, next) {
    try {
        const { modelId } = ctx.request.body;
        // 获取文件夹数组集合 和 文件数组集合
        const { prefixesArr, objectsArr } = await getPathArr(modelId);

        // 目录生成
        await downFile(prefixesArr);
        // 文件下载到对应目录中
        await downFile(objectsArr, 'prefixes', modelId);

        // 前端请求返回
        let userfilepath = `src/examplefile/models/${modelId}.zip`;
        let resultData;
        let stat = fs.readFileSync(`src/examplefile/models/${modelId}.zip`);
        if(fs.existsSync(userfilepath)) {
            resultData = stat.toString('base64');
        } else {
            resultData = { code: 500,message: "模型文件不存在"};
        }

        ctx.body = resultData;
    } catch (e) {
        console.log(e);
    }
}

image.png

总结

时间过得总是好快,一转眼就过了午休的时间,一转眼也快走过了三年,这篇文章只是对需求的分析和初步的代码实现,大家看着图一乐就好,今天上午我们新的领导给我们开会了,这里与大家共勉:
1.找重点的事来做。
2.让自己有时间思考。
3.自身为核心。

最后

水平有限,还不能写到尽善尽美,希望大家多多交流,跟春野一同进步!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
阿里云OSS提供了文件预览的API,您可以使用该API在网页中直接预览OSS存储桶中的文件。具体实现方式如下: 1. 首先,您需要使用阿里云OSS SDK获取文件的URL地址。例如,使用Node.js SDK可以使用以下代码获取文件URL: ```javascript const OSS = require('ali-oss'); // 创建OSS客户端实例 const client = new OSS({ region: 'oss-cn-hangzhou', accessKeyId: 'YOUR_ACCESS_KEY', accessKeySecret: 'YOUR_ACCESS_SECRET', bucket: 'YOUR_BUCKET_NAME' }); // 获取文件URL const objectName = 'example.jpg'; const url = client.signatureUrl(objectName); ``` 上述代码中,`signatureUrl`方法用于生成签名URL,可以在浏览器中直接访问。 2. 接下来,您可以使用第三方库来实现文件预览功能。例如,使用ViewerJS库可以在网页中预览PDF、ODF、ODP、ODS、ODT、PPTX、DOCX、XLSX等格式的文件。具体实现方式如下: ```html <!-- 引入ViewerJS库 --> <script src="https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.9.2/viewer.min.js"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.9.2/viewer.min.css" /> <!-- 创建预览标签 --> <div id="viewer"></div> <!-- 初始化ViewerJS --> <script> const url = 'https://your-bucket.oss-cn-hangzhou.aliyuncs.com/example.pdf'; const viewer = new Viewer(document.getElementById('viewer'), { url: url, toolbar: { zoomIn: 4, zoomOut: 4, oneToOne: true, reset: true, prev: true, play: true, next: true, rotateLeft: true, rotateRight: true, flipHorizontal: true, flipVertical: true, }, }); </script> ``` 上述代码中,首先引入ViewerJS库,并在页面中创建一个`<div>`标签用于显示预览文件。然后,使用ViewerJS库初始化预览标签,并设置预览文件的URL地址。需要注意的是,以上示例中预览的文件为PDF格式,如果需要预览其他格式的文件,需要相应地修改ViewerJS的配置选项。 除了ViewerJS,还可以使用其他第三方库来实现文件预览功能,具体实现方式取决于您的应用程序和所需的功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值