javascript - 复制文件/对象并更改名称
问题描述
我正在为画廊做一个 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
})
})
}
})
},
}
解决方案
这是一个函数,它在传递给它的目录中查找名称为某个数字序列的文件,然后按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);
});
推荐阅读
- c++ - MATLAB 到 C++ Mex 命令选项
- npm - 带有 mocha 的 npm 测试任务继续运行
- python - 是否可以将额外数据作为参数传递给 django 管理表单?
- javascript - 动画完成后元素消失jquery
- android - 如果选中两个 RadioGroup,如何启用按钮?
- php - php jquery ajax 用于表单验证但不用于提交
- php - 从构造函数 Codeigniter 3 中调用的方法返回 JSON 响应
- terraform - 具有相同变量的多个 IP 的 Terraform 模板
- python - 从 json 文件中读取 int
- html - Bootstrap 5 固定导航滚动一点