如何使用node.js同步检查文件或目录是否存在?


当前回答

path模块不提供path.exists的同步版本,因此必须使用fs模块。

我能想到的最快的事情是使用fs.realpathSync,它将抛出一个必须捕获的错误,因此您需要使用try/catch创建自己的包装函数。

其他回答

多年来,这个问题的答案发生了变化。目前的答案在顶部,接下来是多年来按时间顺序排列的各种答案:

当前答案

可以使用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()不使用回调。)

这里有一个简单的包装解决方案:

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()似乎是最优雅的解决方案。

很可能,如果你想知道文件是否存在,你计划在它存在的时候需要它。

function getFile(path){
    try{
        return require(path);
    }catch(e){
        return false;
    }
}

另一个更新

我自己需要这个问题的答案,我查阅了节点文档,似乎您不应该使用fs.exists,而是使用fs.open并使用输出的错误来检测文件是否不存在:

从文档中:

fs.exists()是一个时代错误,只因历史原因而存在。在您自己的代码中使用它几乎没有任何理由。特别是,在打开文件之前检查文件是否存在让你容易受到种族状况影响的反模式:另一种进程可能会在调用fs.exists()和fs.open()。只需打开文件并在不存在时处理错误那里

http://nodejs.org/api/fs.html#fs_fs_exists_path_callback

为那些“正确”指出它不能直接回答问题的人更新了asnwer,更多的是带来了一个替代选项。

同步解决方案:

fs.existsSync('filePath')也可以在此处查看文档。

如果路径存在,则返回true,否则返回false。

Async Promise解决方案

在异步上下文中,您可以使用await关键字编写异步版本同步方法。您可以简单地将异步回调方法转换为如下承诺:

function fileExists(path){
  return new Promise((resolve, fail) => fs.access(path, fs.constants.F_OK, 
    (err, result) => err ? fail(err) : resolve(result))
  //F_OK checks if file is visible, is default does no need to be specified.

}

async function doSomething() {
  var exists = await fileExists('filePath');
  if(exists){ 
    console.log('file exists');
  }
}

access()上的文档。