如何使用node.js同步检查文件或目录是否存在?
当前回答
从答案来看,似乎没有官方的API支持(如直接和明确的检查)。许多答案都说要使用stat,但并不严格。例如,我们不能假设stat抛出的任何错误都意味着某些东西不存在。
让我们试着用一些不存在的东西:
$ node -e 'require("fs").stat("god",err=>console.log(err))'
{ Error: ENOENT: no such file or directory, stat 'god' errno: -2, code: 'ENOENT', syscall: 'stat', path: 'god' }
让我们尝试一下现有但我们无法访问的内容:
$ mkdir -p fsm/appendage && sudo chmod 0 fsm
$ node -e 'require("fs").stat("fsm/appendage",err=>console.log(err))'
{ Error: EACCES: permission denied, stat 'access/access' errno: -13, code: 'EACCES', syscall: 'stat', path: 'fsm/appendage' }
至少你会想要:
let dir_exists = async path => {
let stat;
try {
stat = await (new Promise(
(resolve, reject) => require('fs').stat(path,
(err, result) => err ? reject(err) : resolve(result))
));
}
catch(e) {
if(e.code === 'ENOENT') return false;
throw e;
}
if(!stat.isDirectory())
throw new Error('Not a directory.');
return true;
};
问题还不清楚,是你真的希望它是同步的,还是你只希望它写得像是同步的。此示例使用await/async,因此它只以同步方式编写,但以异步方式运行。
这意味着你必须在顶层这样称呼它:
(async () => {
try {
console.log(await dir_exists('god'));
console.log(await dir_exists('fsm/appendage'));
}
catch(e) {
console.log(e);
}
})();
另一种方法是在异步调用返回的promise上使用.then和.catch。
如果你想检查某个东西是否存在,那么最好确保它是正确类型的东西,比如目录或文件。这包括在示例中。如果不允许使用符号链接,则必须使用lstat而不是stat,因为stat将自动遍历链接。
您可以替换此处的所有异步到同步代码,改用statSync。然而,一旦异步和等待成为普遍支持,Sync调用将变得多余,最终将被贬值(否则,您将不得不在所有地方和链上定义它们,就像异步一样,使其变得毫无意义)。
其他回答
这里有一个简单的包装解决方案:
var fs = require('fs')
function getFileRealPath(s){
try {return fs.realpathSync(s);} catch(e){return false;}
}
用法:
适用于目录和文件如果项存在,则返回文件或目录的路径如果项不存在,则返回false
例子:
var realPath,pathToCheck='<your_dir_or_file>'
if( (realPath=getFileRealPath(pathToCheck)) === false){
console.log('file/dir not found: '+pathToCheck);
} else {
console.log('file/dir exists: '+realPath);
}
确保使用==运算符测试return是否等于false。在适当的工作条件下,fs.realpathSync()返回false是没有逻辑原因的,所以我认为这应该可以100%工作。
我更希望看到一个不会产生错误和性能影响的解决方案。从API的角度来看,fs.exists()似乎是最优雅的解决方案。
const fs = require('fs');
检查以下功能,
if(fs.existsSync(<path_that_need_to_be_checked>)){
// enter the code to excecute after the folder is there.
}
else{
// Below code to create the folder, if its not there
fs.mkdir('<folder_name>', cb function);
}
多年来,这个问题的答案发生了变化。目前的答案在顶部,接下来是多年来按时间顺序排列的各种答案:
当前答案
可以使用fs.existsSync():
const fs = require("fs"); // Or `import fs from "fs";` with ESM
if (fs.existsSync(path)) {
// Do something
}
它已经被弃用了好几年,但现在已经不再使用了
请注意,fs.exists()已弃用,但fs.existsSync()未弃用。(fs.exists()的回调参数接受以下参数与其他Node.js回调不一致。fs.existsSync()不使用回调。)
您已经明确要求进行同步检查,但如果您可以使用异步检查(通常最好使用I/O),如果您使用的是异步函数,请使用fs.promies.access;如果不使用,则使用fs.access(因为不推荐使用exists):
在异步函数中:
try {
await fs.promises.access("somefile");
// The check succeeded
} catch (error) {
// The check failed
}
或使用回调:
fs.access("somefile", error => {
if (!error) {
// The check succeeded
} else {
// The check failed
}
});
历史答案
以下是按时间顺序排列的历史答案:
2010年的原始答案(stat/statSync或lstat/lstatSync)2012年9月更新(存在/存在同步)2015年2月更新(注意到exists/existsSync即将被弃用,因此我们可能会回到stat/statSync或lstat/lstatSync)2015年12月更新(还有fs.access(路径,fs.F_OK,function(){})/fs.accessSync(路径,fs.F_OK),但请注意,如果文件/目录不存在,这是一个错误;fs.stat的文档建议您在不打开的情况下检查是否存在fs.access)2016年12月更新fs.exists()仍被弃用,但fs.existsSync()不再被弃用。所以你现在可以安全地使用它。
2010年的原始答案:
您可以使用statSync或lstatSync(docs链接),这为您提供了一个fs.Stats对象。通常,如果一个函数的同步版本可用,那么它的名称将与异步版本的名称相同,结尾为Sync。所以statSync是stat的同步版本;lstatSync是lstat等的同步版本。
lstatSync告诉您是否存在某个东西,如果存在,它是文件还是目录(或者在某些文件系统中,是符号链接、块设备、字符设备等),例如,如果您需要知道它是否存在并且是一个目录:
var fs = require('fs');
try {
// Query the entry
stats = fs.lstatSync('/the/path');
// Is it a directory?
if (stats.isDirectory()) {
// Yes it is
}
}
catch (e) {
// ...
}
…类似地,如果是文件,则有isFile;如果是块设备,则有isBlockDevice等。请注意try/catch;如果条目根本不存在,它将抛出一个错误。
如果您不关心条目是什么,只想知道它是否存在,那么可以使用path.existsSync(或使用最新的fs.existsSync),如用户618408所示:
var path = require('path');
if (path.existsSync("/the/path")) { // or fs.existsSync
// ...
}
它不需要尝试/捕获,但不提供有关内容的信息,只是它在那里。path.existsSync早就被弃用了。
附带说明:您明确询问了如何同步检查,因此我使用了上述函数的xyzSync版本。但在可能的情况下,对于I/O,最好避免同步调用。从CPU的角度来看,调用I/O子系统需要大量时间。注意调用lstat而不是lstatSync是多么容易:
// Is it a directory?
lstat('/the/path', function(err, stats) {
if (!err && stats.isDirectory()) {
// Yes it is
}
});
但如果您需要同步版本,它就在那里。
2012年9月更新
以下几年前的答案现在有点过时了。当前的方法是使用fs.existsSync来同步检查文件/目录是否存在(当然,fs.exists用于异步检查),而不是下面的路径版本。
例子:
var fs = require('fs');
if (fs.existsSync(path)) {
// Do something
}
// Or
fs.exists(path, function(exists) {
if (exists) {
// Do something
}
});
2015年2月更新
现在是2015年,节点文档现在说fs.existsSync(和fs.exists)“将被弃用”。(因为Node的人认为,在打开某个东西之前检查它是否存在是愚蠢的;但这并不是检查是否存在的唯一原因!)
所以我们可能回到了各种统计方法。。。当然,除非这种情况再次发生变化。
2015年12月更新
不知道它已经存在了多久,但也有fs.access(路径,fs.F_OK,…)/fs.accessSync(路径,fs.F_OK)。至少在2016年10月,fs.stat文档建议使用fs.access来进行存在性检查(“若要检查文件是否存在,而不在事后对其进行操作,建议使用fs.access()。”)。但请注意,访问不可用被视为错误,因此,如果您希望文件可以访问,这可能是最好的:
var fs = require('fs');
try {
fs.accessSync(path, fs.F_OK);
// Do something
} catch (e) {
// It isn't accessible
}
// Or
fs.access(path, fs.F_OK, function(err) {
if (!err) {
// Do something
} else {
// It isn't accessible
}
});
2016年12月更新
可以使用fs.existsSync():
if (fs.existsSync(path)) {
// Do something
}
它已经被弃用了好几年,但现在已经不再使用了
请注意,fs.exists()已弃用,但fs.existsSync()未弃用。(fs.exists()的回调参数接受以下参数与其他Node.js回调不一致。fs.existsSync()不使用回调。)
path模块不提供path.exists的同步版本,因此必须使用fs模块。
我能想到的最快的事情是使用fs.realpathSync,它将抛出一个必须捕获的错误,因此您需要使用try/catch创建自己的包装函数。
查看源代码,有一个同步版本的path.exists-path.existsSync。看起来文档中没有找到它。
更新:
path.exists和path.existsSync现在已弃用。请使用fs.exists和fs.existsSync。
2016年更新:
fs.exists和fs.existsSync也已被弃用。请改用fs.stat()或fs.access()。
2019年更新:
使用fs.existsSync。它没有被弃用。https://nodejs.org/api/fs.html#fs_fs_existssync_path
推荐文章
- NPM清洁模块
- 在Node.js中加载基本HTML
- Node.js和CPU密集型请求
- 为什么在节点REPL中没有定义__dirname ?
- 在Node.js中克隆对象
- Node.js中的process.env.PORT是什么?
- js的Mongoose.js字符串到ObjectId函数
- ELIFECYCLE Node.js错误是什么意思?
- 如何完全卸载Ubuntu中的nodejs, npm和node
- 在猫鼬模式中添加created_at和updated_at字段
- 我如何把变量javascript字符串?
- 如何强制tsc忽略node_modules文件夹?
- NPM全局安装“无法找到模块”
- MongoDB和Mongoose的区别
- 如何使用Express.js指定HTTP错误码?