Node.js 创建文件夹或使用现有的
Posted
技术标签:
【中文标题】Node.js 创建文件夹或使用现有的【英文标题】:Node.js create folder or use existing 【发布时间】:2012-11-21 16:19:23 【问题描述】:我已经阅读过 Node.js 的文档,除非我遗漏了什么,否则它不会说明某些操作中的参数包含什么,尤其是 fs.mkdir()
。正如您在文档中看到的那样,它不是很多。
目前,我有这段代码,它试图创建一个文件夹或使用现有文件夹:
fs.mkdir(path,function(e)
if(!e || (e && e.code === 'EEXIST'))
//do something with contents
else
//debug
console.log(e);
);
但我想知道这是正确的方法吗?检查代码EEXIST
是否是知道该文件夹已经存在的正确方法?我知道我可以在创建目录之前执行fs.stat()
,但这已经是对文件系统的两次点击。
其次,是否有完整的或至少更详细的 Node.js 文档,其中包含有关错误对象包含的内容、参数的含义等详细信息。
【问题讨论】:
小挑剔,但摆脱e &&
。如果!e
失败,那么你知道e
是真的。
【参考方案1】:
在我看来,您最好不要在使用 javascript 编写代码时计算文件系统的命中次数。
但是,(1) stat
& mkdir
和 (2) mkdir
并检查(或丢弃)错误代码,这两种方法都是做你想做的事情的正确方法。
【讨论】:
这是 mkdir 目录或使用现有目录的好方法。我不明白你为什么看不到。检查错误代码是一种礼貌的好方法,而丢弃错误代码只是一种好方法。你不同意吗? 我明白你的意思了。但是,我相信有很多方法可以正确地做事。谢谢。【参考方案2】:fs.mkdir
的 node.js 文档基本上遵循mkdir(2)
的 Linux 手册页。这表明EEXIST
如果路径存在但不是一个目录,如果你走这条路,也会被指示出来。
您最好致电fs.stat
,它会告诉您该路径是否存在以及它是否是一次调用中的目录。对于(我假设是)目录已经存在的正常情况,它只是一个文件系统命中。
这些 fs
模块方法是原生 C API 的精简包装器,因此您必须查看 node.js 文档中引用的手册页以了解详细信息。
【讨论】:
在mkdir
之前调用stat
可能会出现竞争条件——请记住这一点。【参考方案3】:
这样做的好方法是使用mkdirp 模块。
$ npm install mkdirp
使用它来运行需要目录的功能。在创建路径或路径确实已经存在时调用回调。如果 mkdirp 创建目录路径失败,则会设置错误 err
。
var mkdirp = require('mkdirp');
mkdirp('/tmp/some/path/foo', function(err)
// path exists unless there was an error
);
【讨论】:
在我看来,正确的(阅读“不添加依赖项”)答案将是@Raugaral 使用fs.exists(Sync)
的答案。
@RicardoPedroni 正确的方法是使用模块。模块通常全心全意地尝试解决一个问题,并且经常被维护。您可以使用 npm 轻松更新它们。此外,您应该特别避免使用 fs.exists[Sync],因为它的使用意味着竞争条件。
@1j01 如果平台本身支持该操作,我不认为正确的方法是使用模块。这是一条通往混乱的道路。我不得不同意从技术角度来看有更好的答案。
@1j01 此外,使用同步操作意味着竞争条件,因为它们的使用是对它们的解决方案。
为什么不使用内部节点fs
功能?【参考方案4】:
你可以用这个:
if(!fs.existsSync("directory"))
fs.mkdirSync("directory", 0766, function(err)
if(err)
console.log(err);
// echo the result back
response.send("ERROR! Can't make the directory! \n");
);
【讨论】:
-1。我不相信这行得通,如果实体根本不存在,statSync
将引发错误,从而使代码崩溃。您需要将其包装在 try/catch
块中。
对不起,我错了。将“statSync”更改为“existsSync”
根据nodejs.org/api/fs.html#fs_fs_mkdirsync_path_mode mkdir 的同步变体不接受回调
根据nodejs.org/api/fs.html#fs_fs_existssync_path,fs.existsSync()
和fs.exists()
将被弃用。
错了。由于回调参数不兼容,fs.exists() 已被弃用。 fs.existsSync() 方法仍然有效。【参考方案5】:
编辑: 因为这个答案很受欢迎,我已经更新它以反映最新的做法。
节点 >=10
Node 的 fs
的新 recursive: true
选项现在本机允许这样做。此选项模仿 UNIX 的 mkdir -p
的行为。它将递归地确保路径的每个部分都存在,并且如果其中任何部分存在,则不会抛出错误。
(注意:它可能仍然会抛出诸如EPERM
或EACCESS
之类的错误,因此如果您的实现容易受到它的影响,最好还是将其包装在try catch (e)
中。)
同步版本。
fs.mkdirSync(dirpath, recursive: true )
异步版本
await fs.promises.mkdir(dirpath, recursive: true )
旧节点版本
使用try catch (err)
,您可以非常优雅地实现这一目标,而不会遇到竞争条件。
为了防止检查存在和创建目录之间的死时间,我们只是尝试直接创建它,如果是EEXIST
(目录已经存在)则忽略错误。
如果错误不是EEXIST
,但是,我们应该抛出一个错误,因为我们可能正在处理类似EPERM
或EACCES
的东西
function ensureDirSync (dirpath)
try
return fs.mkdirSync(dirpath)
catch (err)
if (err.code !== 'EEXIST') throw err
对于mkdir -p
-like 递归行为,例如./a/b/c
,您必须在 dirpath 的每个部分都调用它,例如./a
、./a/b
、.a/b/c
【讨论】:
var fs = Npm.require('fs'); var dir = process.env.PWD + '/files/users/' + this.userId + '/';试试 fs.mkdirSync(dir); catch (e) if (e.code != 'EEXIST') throw e; 我试过你的代码,创建一个使用目录创建的 js 脚本,如下所示: mkdirpSync(path.join(__dirname, 'first', 'second', 'third', 'ololol', '作品'));但是得到了这个错误:$ node 1.js fs.js:747 return binding.mkdir(pathModule._makeLong(path), ^ Error: EPERM, operation not allowed 'C:\' at Error (native) at Object.fs。 mkdirSync (fs.js:747:18) 在 mkdirpSync (C:\Users\MAXIM\Desktop\test\1.js:15:8) 在 Object. (C:\Users\MAXIM\Desktop\test\ 1.js:19:1) ...你能提出什么问题吗?显然在 Windows 上使用 :) EPERM 似乎是一个权限问题,所以脚本无论如何都会中断执行 我认为这样会更好: var mkdirpSync = function (dirpath) var parts = dirpath.split(path.sep); for( var i = 1; i 警告:如果您的路径以 / 开头,它将不起作用【参考方案6】:如果你想要一个又快又脏的衬里,使用这个:
fs.existsSync("directory") || fs.mkdirSync("directory");
【讨论】:
fs.exists
已弃用:nodejs.org/api/fs.html#fs_fs_exists_path_callback
fs.existsSync(...) 虽然没有被弃用,所以这个答案似乎还可以。
注意!不适用于“dir/foo/bar”,即缺少 mkdir -p 标志功能
这也有竞争条件【参考方案7】:
你也可以使用fs-extra,它提供了很多常用的文件操作。
示例代码:
var fs = require('fs-extra')
fs.mkdirs('/tmp/some/long/path/that/prob/doesnt/exist', function (err)
if (err) return console.error(err)
console.log("success!")
)
fs.mkdirsSync('/tmp/another/path')
这里的文档:https://github.com/jprichardson/node-fs-extra#mkdirsdir-callback
【讨论】:
【参考方案8】:为每个用户创建动态名称目录...使用此代码
***suppose email contain user mail address***
var filessystem = require('fs');
var dir = './public/uploads/'+email;
if (!filessystem.existsSync(dir))
filessystem.mkdirSync(dir);
else
console.log("Directory already exist");
【讨论】:
【参考方案9】:这是我用来创建目录的 ES6 代码(当它不存在时):
const fs = require('fs');
const path = require('path');
function createDirectory(directoryPath)
const directory = path.normalize(directoryPath);
return new Promise((resolve, reject) =>
fs.stat(directory, (error) =>
if (error)
if (error.code === 'ENOENT')
fs.mkdir(directory, (error) =>
if (error)
reject(error);
else
resolve(directory);
);
else
reject(error);
else
resolve(directory);
);
);
const directoryPath = `$__dirname/test`;
createDirectory(directoryPath).then((path) =>
console.log(`Successfully created directory: '$path'`);
).catch((error) =>
console.log(`Problem creating directory: $error.message`)
);
注意:
在createDirectory
函数的开头,我规范了路径以保证操作系统的路径分隔符类型将被一致地使用(例如这会将C:\directory/test
变成C:\directory\test
(在Windows上)
fs.exists
是deprecated,所以我使用fs.stat
来检查目录是否已经存在
如果目录不存在,错误代码将为ENOENT
(Error NO ENTry)
目录本身将使用fs.mkdir
创建
我更喜欢异步函数fs.mkdir
,而不是它的阻塞对应函数fs.mkdirSync
,并且由于包装Promise
,它将保证只有在成功创建目录后才会返回目录的路径
【讨论】:
感谢您提供不涉及不必要模块的干净解决方案。它对我来说非常有效。我希望有更多这样的答案!【参考方案10】:我提出了一个没有模块的解决方案(为了可维护性,从不建议使用累积模块,尤其是对于可以用几行编写的小功能......):
最后更新:
在 v10.12.0 中,NodeJS 实现了递归选项:
// Create recursive folder
fs.mkdir('my/new/folder/create', recursive: true , (err) => if (err) throw err; );
更新:
// Get modules node
const fs = require('fs');
const path = require('path');
// Create
function mkdirpath(dirPath)
if(!fs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK))
try
fs.mkdirSync(dirPath);
catch(e)
mkdirpath(path.dirname(dirPath));
mkdirpath(dirPath);
// Create folder path
mkdirpath('my/new/folder/create');
【讨论】:
fs.exists()
在节点 v9 中已弃用。请改用fs.access()
。 (如果文件存在则返回undefined
;否则抛出错误ENOENT
)
没有任何 npm 包,它可以工作。这是一个有价值的代码。谢谢
这个更适合在现有长路径下创建文件夹;)谢谢,伙计。
fs.mkdirSync('my/new/folder/create', recursive: true)
呢?
谢谢!我更新我的帖子以帮助其他人。节点 10.12.0 太新了。【参考方案11】:
Raugaral's answer 但带有 -p 功能。丑陋,但它有效:
function mkdirp(dir)
let dirs = dir.split(/\\/).filter(asdf => !asdf.match(/^\s*$/))
let fullpath = ''
// Production directory will begin \\, test is on my local drive.
if (dirs[0].match(/C:/i))
fullpath = dirs[0] + '\\'
else
fullpath = '\\\\' + dirs[0] + '\\'
// Start from root directory + 1, build out one level at a time.
dirs.slice(1).map(asdf =>
fullpath += asdf + '\\'
if (!fs.existsSync(fullpath))
fs.mkdirSync(fullpath)
)
//mkdirp
【讨论】:
【参考方案12】:正如Teemu Ikonen's answer 的新替代品一样,它非常简单易读,是使用fs-extra
包的ensureDir
方法。
它不仅可以公然替代内置的fs
模块,而且除了fs
包的功能外,还有很多其他的功能。
ensureDir
方法,顾名思义,确保目录存在。如果目录结构不存在,则创建它。喜欢mkdir -p
。不只是结束文件夹,而是创建整个路径(如果不存在)。
上面提供的是它的async
版本。它还有一个同步方法来执行此操作,形式为ensureDirSync
方法。
【讨论】:
【参考方案13】:您可以使用文件系统模块完成所有这些操作。
const
fs = require('fs'),
dirPath = `path/to/dir`
// Check if directory exists.
fs.access(dirPath, fs.constants.F_OK, (err)=>
if (err)
// Create directory if directory does not exist.
fs.mkdir(dirPath, recursive:true, (err)=>
if (err) console.log(`Error creating directory: $err`)
else console.log('Directory created successfully.')
)
// Directory now exists.
)
您甚至不需要检查目录是否存在。以下代码还保证该目录已经存在或已创建。
const
fs = require('fs'),
dirPath = `path/to/dir`
// Create directory if directory does not exist.
fs.mkdir(dirPath, recursive:true, (err)=>
if (err) console.log(`Error creating directory: $err`)
// Directory now exists.
)
【讨论】:
【参考方案14】:@Liberateur 的 answer above 对我不起作用(节点 v8.10.0)。 一点点修改就可以了,但我不确定这是否是正确的方法。请提出建议。
// Get modules node
const fs = require('fs');
const path = require('path');
// Create
function mkdirpath(dirPath)
try
fs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK);
catch(err)
try
fs.mkdirSync(dirPath);
catch(e)
mkdirpath(path.dirname(dirPath));
mkdirpath(dirPath);
// Create folder path
mkdirpath('my/new/folder/create');
【讨论】:
以上是关于Node.js 创建文件夹或使用现有的的主要内容,如果未能解决你的问题,请参考以下文章
node.js+mongoose UserSchema findOrCreate