如果文件或目录存在,如何使用 node.js 进行同步检查?
答案 0 :(得分:1961)
多年来,这个问题的答案发生了变化。 当前答案位于顶部,随后按时间顺序排列多年来的各种答案:
您可以使用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),请使用{{3}如果您正在使用async
函数或fs.promises.access
(因为exists
已弃用),否则(因为fs.exists
已弃用):
在async
函数中:
try {
await fs.promises.access("somefile");
// The check succeeded
} catch (error) {
// The check failed
}
或者使用回调:
fs.access("somefile", error => {
if (!error) {
// The check succeeded
} catch (error) {
// The check failed
}
});
以下是按时间顺序排列的历史答案:
stat
/ statSync
或lstat
/ lstatSync
)exists
/ existsSync
)exists
/ existsSync
即将弃用,因此我们可能会回到stat
/ statSync
或lstat
/ {{1} })lstatSync
/ fs.access(path, fs.F_OK, function(){})
,但请注意,如果文件/目录不存在,则表示错误; fs.accessSync(path, fs.F_OK)
的文档建议使用fs.stat
如果你需要检查存在而不打开)fs.access
,但不再弃用fs.exists()
。所以你现在可以安全地使用它。您可以使用fs.existsSync()
或statSync
(fs.access
),这会为您提供docs link。通常,如果某个函数的同步版本可用,它将与最终版本为lstatSync
的异步版本具有相同的名称。因此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
;如果条目根本不存在则抛出错误。
如果你不关心 条目是什么,只想知道它是否存在,你可以使用 fs.Stats
object(或最新的,try/catch
)path.existsSync
:
fs.existsSync
它不需要 var path = require('path');
if (path.existsSync("/the/path")) { // or fs.existsSync
// ...
}
,但是没有提供有关该内容的信息,只是它就在那里。try/catch
已被弃用了很长时间前。
附注:您已明确询问如何同步检查 ,因此我使用了上述函数的path.existsSync
版本。但只要有可能,使用I / O,最好避免同步调用。从CPU的角度来看,调用I / O子系统需要很长时间。请注意,调用noted by user618408而非xyzSync
:
lstatSync
但是如果你需要同步版本,它就在那里。
几年前的答案现在有点过时了。目前的方法是使用lstat
对文件/目录存在进行同步检查(当然,fs.existsSync
进行异步检查),而不是下面的// Is it a directory?
lstat('/the/path', function(err, stats) {
if (!err && stats.isDirectory()) {
// Yes it is
}
});
版本。
示例:
path
现在我们在2015年,Node文档现在声明var fs = require('fs');
if (fs.existsSync(path)) {
// Do something
}
// Or
fs.exists(path, function(exists) {
if (exists) {
// Do something
}
});
(和fs.existsSync
)“将被弃用”。 (因为节点的人认为在打开它之前检查某些东西是否存在是愚蠢的,这是不正确的;但这不是检查某些东西是否存在的唯一原因!)
所以我们可能会回到各种fs.exists
方法......直到/除非这种情况再次发生变化,当然。
不知道它有多久,但也有fs.exists
。至少截至2016年10月,fs.access(path, fs.F_OK, ...)
/ fs.accessSync(path, fs.F_OK)
建议使用stat
进行存在检查(“要检查文件是否存在而不进行操作,建议使用fs.access
。” )。但请注意,访问权限不可用被视为错误,因此如果您希望可以访问该文件,这可能是最佳选择:
fs.access()
您可以使用fs.stat
documentation:
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
}
});
它被推荐了几年,但不再是。来自文档:
请注意,
if (fs.existsSync(path)) { // Do something }
已弃用,但fs.exists()
未弃用。 (该fs.existsSync()
的回调参数接受的参数 与其他Node.js回调不一致。fs.exists()
没有 使用回调。)
答案 1 :(得分:118)
查看来源,有path.exists
- path.existsSync
的同步版本。看起来它在文档中被遗漏了。
path.exists
和path.existsSync
现已已弃用。 请使用。fs.exists
和fs.existsSync
fs.exists
和fs.existsSync
也已被弃用。请改用fs.stat()或fs.access()。
答案 2 :(得分:53)
使用当前推荐的(截至2015年)API(根据Node文档),这就是我的工作:
var fs = require('fs');
function fileExists(filePath)
{
try
{
return fs.statSync(filePath).isFile();
}
catch (err)
{
return false;
}
}
在回应@broadband在评论中提出的EPERM问题时,这提出了一个很好的观点。在许多情况下,fileExists()可能不是一个考虑这个问题的好方法,因为fileExists()实际上无法承诺布尔返回。您可以明确确定该文件是否存在或不存在,但您也可能会收到权限错误。权限错误并不一定意味着文件存在,因为您可能缺少包含要检查的文件的目录的权限。当然,在检查文件存在时,您可能会遇到其他错误。
所以我上面的代码实际上是doFileExistAndDoIHaveAccessToIt(),但你的问题可能是doFileNotExistAndCouldICreateIt(),这将是完全不同的逻辑(需要考虑EPERM错误等)。
虽然fs.existsSync答案直接解决了这里提出的问题,但通常不会是你想要的(你不想知道是否"某些东西"存在于路径中,你可能关心存在的"事物是否是文件或目录。
最重要的是,如果您要检查文件是否存在,那么您可能正在这样做,因为您打算根据结果和逻辑(检查和/或后续操作)采取某些操作)应该容纳在该路径中找到的东西可能是文件或目录的想法,并且您在检查过程中可能会遇到EPERM或其他错误。
答案 3 :(得分:20)
另一次更新
我自己找到了这个问题的答案我查了节点文档,似乎你应该不使用fs.exists,而是使用fs.open并使用输出错误来检测文件是否没有存在:
来自文档:
fs.exists()是一种时代错误,只是出于历史原因而存在。 几乎没有理由在你自己的代码中使用它。
特别是,在打开文件之前检查文件是否存在是一个 让你容易受到竞争条件影响的反模式:另一种 进程可能会在调用fs.exists()和之间删除文件 fs.open()。只需打开文件并处理错误即可 那里。
答案 4 :(得分:11)
我使用下面的函数来测试文件是否存在。它还捕获了其他例外情况。因此,如果存在权利问题,例如chmod ugo-rwx filename
或在Windows中
Right Click -> Properties -> Security -> Advanced -> Permission entries: empty list ..
函数返回异常。该文件存在,但我们无权访问它。忽略这种例外是错误的。
function fileExists(path) {
try {
return fs.statSync(path).isFile();
}
catch (e) {
if (e.code == 'ENOENT') { // no such file or directory. File really does not exist
console.log("File does not exist.");
return false;
}
console.log("Exception fs.statSync (" + path + "): " + e);
throw e; // something else went wrong, we don't have rights, ...
}
}
异常输出,nodejs errors documentation,如果文件不存在:
{
[Error: ENOENT: no such file or directory, stat 'X:\\delsdfsdf.txt']
errno: -4058,
code: 'ENOENT',
syscall: 'stat',
path: 'X:\\delsdfsdf.txt'
}
如果我们对该文件没有权限但存在,则为例外:
{
[Error: EPERM: operation not permitted, stat 'X:\file.txt']
errno: -4048,
code: 'EPERM',
syscall: 'stat',
path: 'X:\\file.txt'
}
答案 5 :(得分:5)
fs.exists()已弃用,请勿使用https://nodejs.org/api/fs.html#fs_fs_exists_path_callback
您可以实现此处使用的核心nodejs方式: https://github.com/nodejs/node-v0.x-archive/blob/master/lib/module.js#L86
function statPath(path) {
try {
return fs.statSync(path);
} catch (ex) {}
return false;
}
这将返回stats对象,然后一旦你有了你可以尝试的stats对象
var exist = statPath('/path/to/your/file.js');
if(exist && exist.isFile()) {
// do something
}
答案 6 :(得分:4)
此处的一些答案表示fs.exists
和fs.existsSync
均已弃用。根据文档,这不再是真实的。现在只删除了fs.exists
:
请注意,不推荐使用fs.exists(),但不推荐使用fs.existsSync()。 (该 fs.exists()的回调参数接受的参数 与其他Node.js回调不一致。 fs.existsSync()没有 使用回调。)
因此,您可以安全地使用fs.existsSync()来同步检查文件是否存在。
答案 7 :(得分:2)
path
模块未提供path.exists
的同步版本,因此您必须使用fs
模块进行操作。
我能想象的最快的事情是使用fs.realpathSync
会抛出你必须捕获的错误,所以你需要使用try / catch创建自己的包装函数。
答案 8 :(得分:1)
您可以使用 fs-extra (npm i fs-extra) 及其 fs.ensureFile 或用于目录 fs.ensureDir,因为 fs.exists 已被弃用并且 fs.access 不建议您在之后编辑该文件使用它“在调用 fs.open()、fs.readFile() 或 fs.writeFile() 之前,不要使用 fs.access() 检查文件的可访问性。这样做会引入竞争条件,因为其他进程可能在两次调用之间更改文件的状态。相反,用户代码应直接打开/读取/写入文件,并在文件不可访问时处理引发的错误。”
答案 9 :(得分:1)
这已经有人回答了,但如果你喜欢安装模块,你可以使用 dtfe
,它代表
文件存在吗?
const dtfe = require('dtfe');
dtfe('package.json');
//=> true
答案 10 :(得分:0)
如果您不打算操作该文件,fs.stat()
上的文档会说使用fs.access()
。它没有给出理由,可能更快或更少使用记忆?
我使用node进行线性自动化,所以我想我分享了用来测试文件存在的函数。
var fs = require("fs");
function exists(path){
//Remember file access time will slow your program.
try{
fs.accessSync(path);
} catch (err){
return false;
}
return true;
}
答案 11 :(得分:0)
如果您想知道文件是否存在,则有可能计划将其存在。
function getFile(path){
try{
return require(path);
}catch(e){
return false;
}
}
答案 12 :(得分:0)
安装
npm i graph-fs
使用
const {Node} = require("graph-fs");
const directory = new Node("/path/to/directory");
directory.exists; // <--
答案 13 :(得分:0)
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);
}
答案 14 :(得分:0)
使用fileSystem(fs)测试将触发错误对象,然后您需要将其包装在try / catch语句中。省下一些功夫,并使用0.4.x分支中的功能介绍。
var path = require('path');
var dirs = ['one', 'two', 'three'];
dirs.map(function(dir) {
path.exists(dir, function(exists) {
var message = (exists) ? dir + ': is a directory' : dir + ': is not a directory';
console.log(message);
});
});
答案 15 :(得分:-1)
以下是一个简单的包装解决方案:
var fs = require('fs')
function getFileRealPath(s){
try {return fs.realpathSync(s);} catch(e){return 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()似乎是最优雅的解决方案。
答案 16 :(得分:-2)
为那些人正确更新了#n;&#39;指出它没有直接回答这个问题,更多的是带来另一种选择。
let reg = /^(_|)\w*.(sass|less|scss)$/,
arr = [
'a.scss',
'_a.scss',
'a_b.scss'
];
arr.forEach(function( filename ) {
console.log( filename + '\t' + reg.test(filename) );
});
也see docs here。
如果路径存在则返回true,否则返回false。
在异步上下文中,您可以使用fs.existsSync('filePath')
关键字在同步方法中编写异步版本。您可以简单地将异步回调方法转换为这样的承诺:
await
访问()上的
答案 17 :(得分:-2)
从答案中可以看出,没有正式的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);
}
})();
另一种方法是使用.then和.catch对异步调用返回的promise进行进一步调低。
如果要检查是否存在某些内容,那么最好还是确保它是正确的类型,例如目录或文件。这包含在示例中。如果不允许使用符号链接,则必须使用lstat而不是stat,因为stat将自动遍历链接。
您可以在此处替换所有异步同步代码,而是使用statSync。然而,一旦异步和等待变得普遍支持,同步调用最终将变得多余,以便折旧(否则你将不得不在各处定义它们,就像异步一样使它变得毫无意义)。