首页 > 解决方案 > 复制文件/对象并更改名称

问题描述

我正在为画廊做一个 API;所以,我创建了一个方法,可以从数据库中复制图像。现在,我想在复制图像名称的末尾添加一个数字。例如:

-original image name: image
-copy image name: image(1)
-2nd copy image name: image(2)

如何自动将数字添加到复制名称的名称中?

     'use strict'
        let imageObject= require('../models/image-object');
        let fs=require('fs');
        let path= require('path');
        
        
        
        let gallery_controllers={
        
     
    
           copyImage:function(req,res){         
                
                    //get the id param of the image to copy
                let imageId=req.params.id;
                if(imageId==null) return res.status(404).send({message:"no ID defined"});
        
                    //I search the requiere image on the database
                imageObject.findById(imageId,(err,image)=>{
                    if(err) return res.status(500).send({message:'err to response data'});
                    if(!image) return res.status(404).send({message:'image not found'});
        
                    if(image){
                    //set a new model-object
                        let imageCopied= new imageObject();
                        
                        imageCopied.name= image.name;
                        imageCopied.image=image.image;
        
                    //save image copied on the database
                        imageCopied.save((err,image_copied)=>{
                            if(err) return res.status(500).send({message:"error 500"});
                            if(!image_copied) return res.status(404).send({message:"error 404"});
        
                            return res.status(200).send({
                                image:image_copied
                            })
                        })
                    }
                })
        
            },
        }

标签: javascriptnode.jsmongodbexpressmean-stack

解决方案


这是一个函数,它在传递给它的目录中查找名称为某个数字序列的文件,然后按file(nnn)顺序nnn向您返回下一个文件的完整路径(已存在的最高数字之后的那个)。

此函数使用该名称预先创建一个占位符文件,以避免调用此函数的多个异步操作的并发问题和潜在的冲突(如果它只返回文件名而不创建文件)。为了进一步处理冲突,它会以一种模式创建占位符文件,如果它已经存在则失败(因此只有一次调用此函数将创建该特定文件),如果它遇到冲突,它会自动重试以查找新编号(例如在我们开始之前,其他人创建了下一个可用文件)。所有这些逻辑都是为了避免在创建序列中的下一个文件名时可能出现的竞争条件的微妙之处。

一旦调用者有一个唯一的文件名,这将被解析,那么预计他们将用他们自己的内容覆盖占位符内容。

// pass directory to look in
// pass base file name so it will look for next in sequence as in "file(3)"
// returns the full path of the unique placeholder file it has created
// the caller is then responsible for that file
// calling multiple times will create a new placeholder file each time
async function findNextName(dir, base) {
    let cntr = 0;
    const cntr_max = 5;
    const regex = new RegExp(`^${base}\\((\\d+)\\)$`);

    async function run() {
        const files = await fs.promises.readdir(dir);
        let highest = 0;
        for (let f of files) {
            let matches = f.match(regex);
            if (matches) {
                let num = parseInt(matches[1]);
                if (num > highest) {
                    highest = num;
                }
            }
        }
        let name = `${base}(${highest + 1})`;
        // create placeholder file with this name to avoid concurrency issues
        // of another request also trying to use the same next file
        try {
            // write to file, fail if the file exists due to a concurrency issue
            const fullPath = path.resolve(path.join(dir, name));
            await fs.promises.writeFile(fullPath, "placeholder", { flag: "wx" });
            return fullPath;
        } catch (e) {
            // if this fails because of a potential concurrency issue, then try again
            // up to cntr_max times to avoid looping forever on a persistent error
            if (++cntr < cntr_max) {
                return run();
            } else {
                throw e;
            }
        }
    }
    return run();
}

你可以这样称呼它:

findNextName(".", "file").then(filename=> {
    console.log(filename);
}).catch(err => {
    console.log(err);
});

推荐阅读