同步检查Node.js中是否存在文件/目录

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

这个问题的答案多年来一直在改变。 目前的答案在这里是最高的,随后是按时间顺序排列的各种答案:

当前答案

你可以使用fs.existsSync()

 var fs = require('fs'); if (fs.existsSync(path)) { // Do something } 

它被弃用了几年,但不再是。 从文档:

请注意, fs.exists()已弃用,但fs.existsSync()不适用。 ( fs.exists()的callback参数接受与其他Node.jscallback不一致的参数fs.existsSync()不使用callback。)

您特别要求进行同步检查,但是如果您可以使用asynchronous检查(通常最好使用I / O),请使用fs.access (因为exists已被弃用)。


历史答案

以下是按时间顺序排列的历史答案:

  • 从2010年的原始答复
    stat / statSynclstat / lstatSync
  • 2012年9月更新
    exists / existsSync
  • 2015年2月更新
    (注意exists / existsSync即将弃用,所以我们可能会回到stat / statSynclstat / lstatSync
  • 2015年12月更新
    (还有fs.access(path, fs.F_OK, function(){}) / fs.accessSync(path, fs.F_OK) ,但是请注意,如果文件/目录不存在,则是错误; docs for fs.statbuild议使用fs.access如果你需要检查存在而不打开)
  • 2016年12月更新
    fs.exists()仍然被弃用,但fs.existsSync()不再被弃用。 所以你现在可以安全地使用它。

2010年的原始答案:

你可以使用statSynclstatSync ( docs link ),它给你一个fs.Stats对象 。 一般情况下,如果某个函数的同步版本可用,则它将与具有Sync的asynchronous版本具有相同的名称。 所以statSyncstat的同步版本; lstatSynclstat的同步版本等

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 指出的path.existsSync (或with latest, fs.existsSync ):

 var path = require('path'); if (path.existsSync("/the/path")) { // or fs.existsSync // ... } 

它不需要一个try/catch ,但是没有给你什么信息,只是它在那里。 path很久以前就被弃用了。


注意:你明确地问过如何同步检查,所以我使用了上述函数的xyzSync版本。 但是,只要有可能,使用I / O,确实最好避免同步调用。 从CPU的angular度来看,调用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用于asynchronous检查),而不是下面的path版本。

例:

 var fs = require('fs'); if (fs.existsSync(path)) { // Do something } // Or fs.exists(path, function(exists) { if (exists) { // Do something } }); 

2015年2月更新

在这里,我们在2015年,Node文档现在说fs.existsSync (和fs.exists )“将被弃用”。 (因为Node人认为在打开它之前检查是否存在某个东西是愚蠢的,但是这不是检查是否存在的唯一原因!)

所以我们可能会回到各种stat方法…直到/除非再次改变,当然。

2015年12月更新

不知道有多久,但也有fs.access(path, fs.F_OK, ...) / fs.accessSync(path, fs.F_OK) 。 至less从2016年10月份开始, fs.stat文档build议使用fs.access进行存在检查( “要检查文件是否存在,之后再处理,build议使用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()的callback参数接受与其他Node.jscallback不一致的参数fs.existsSync()不使用callback。)

查看源代码,有一个同步版本的path.existspath.existsSync 。 看起来像在文档中错过了。

更新:

现在不推荐使用 path.existspath.existsSync请使用fs.existsfs.existsSync

2016年更新:

fs.exists和fs.existsSync也被弃用 。 改用fs.stat()或fs.access() 。

使用目前推荐的(截至2015年)API(每个Node文档),这就是我所做的:

 var fs = require('fs'); function fileExists(filePath) { try { return fs.statSync(filePath).isFile(); } catch (err) { return false; } } 

为了回应@broadband在评论中提出的EPERM问题,提出了一个很好的观点。 在许多情况下,fileExists()可能不是一个很好的思考方法,因为fileExists()不能真正承诺布尔返回。 您可能能够明确确定文件是否存在,但是您也可能会收到权限错误。 权限错误并不一定意味着该文件存在,因为您可能缺less对包含您正在检查的文件的目录的权限。 当然,有可能在检查文件存在时遇到其他一些错误。

所以我上面的代码真的是doesFileExistAndDoIHaveAccessToIt(),但你的问题可能是doesFileNotExistAndCouldICreateIt(),这将是完全不同的逻辑(这将需要考虑EPERM错误等)。

虽然fs.existsSync的答案直接解决了这里提出的问题,但这往往不会成为你想要的(你不只是想知道在path中是否存在“某些东西”,你可能会关心“事物”存在的是文件或目录)。

底线是,如果你正在检查一个文件是否存在,你可能是这样做的,因为你打算根据结果采取一些行动,而逻辑(检查和/或后续行动)应该适应这个想法在该path中发现的东西可能是文件或目录,在检查过程中可能会遇到EPERM或其他错误。

另一个更新

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

从文档:

fs.exists()是一个时代错误,只存在于历史原因。 几乎从来没有理由在你自己的代码中使用它。

特别是,在打开文件之前检查文件是否存在是一种反模式,使您容易受到竞争状况的影响:另一个进程可能会在调用fs.exists()和fs.open()之间删除文件。 只要打开文件并在不存在的情况下处理错误。

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

我使用下面的函数来testing文件是否存在。 它也捕捉到其他例外。 所以如果有权利问题,例如chmod ugo-rwx filename或在Windows Right Click -> Properties -> Security -> Advanced -> Permission entries: empty list ..函数返回exception,因为它应该。 该文件存在,但我们无权访问它。 忽略这种例外是错误的。

 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, ... } } 

exception输出,情况文件中的nodejs错误文档不存在:

 { [Error: ENOENT: no such file or directory, stat 'X:\\delsdfsdf.txt'] errno: -4058, code: 'ENOENT', syscall: 'stat', path: 'X:\\delsdfsdf.txt' } 

如果我们对文件没有权限,但存在exception:

 { [Error: EPERM: operation not permitted, stat 'X:\file.txt'] errno: -4048, code: 'EPERM', syscall: 'stat', path: 'X:\\file.txt' } 

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 } 

这里的一些答案说, fs.existsfs.existsSync都被弃用。 根据文件,这是不正确的。 现在只有fs.exists被剥夺了:

请注意,fs.exists()已弃用,但fs.existsSync()不适用。 (fs.exists()的callback参数接受与其他Node.jscallback不一致的参数。fs.existsSync()不使用callback。)

所以你可以安全地使用fs.existsSync()来同步检查一个文件是否存在。

path模块不提供path.exists的同步版本,所以你必须欺骗fs模块。

我可以想象的最快的事情是使用fs.realpathSync ,它将抛出一个错误,你必须赶上,所以你需要使用try / catch来创build自己的包装函数。

使用fileSystem(fs)testing将触发错误对象,然后您将需要包装在try / catch语句中。 节省一些努力,并使用0.4.x分支中的function介绍。

 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); }); }); 

fs.stat()上的文档说如果你不打算操作文件,就使用fs.access() 。 它没有给出一个理由,可能会更快或更lessmemeory使用?

我使用节点进行线性自动化,所以我想我分享我用来testing文件存在的function。

 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; } 

Async Promise解决scheme(bluebirdjs)

对于那些使用bluebirdjs和nodejs 7.返回布尔诺的最好方法是:

 function fileExists(path){ return fs.accessAsync(path, fs.constants.F_OK) //F_OK checks if file is visible, is default does no need to be specified. .then(err => !err); } 

文档: https : //nodejs.org/api/fs.html#fs_fs_access_path_mode_callback

从答案看来,这没有官方的API支持。 许多答案说使用统计,但他们并不严格。 例如,我们不能假设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' } 

至less你会想要:

 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关键字将syncronous转换为asyncronous。 但目前的实施情况很差。 处理到达顶端的exception是特殊的,它要求你把所有标记为asynchronous的callstack。

这意味着你必须在顶层调用它:

 (async () => { try { console.log(await dir_exists('god')); console.log(await dir_exists('fsm/appendage')); } catch(e) { console.log(e); } })(); 

另一种方法是使用.then和.catch从asynchronous调用返回的许诺,如果你需要更进一步。

你当然可以在这里replace所有的asynchronous同步代码,而使用statSync。 然而,期望一旦语言正确地源出asynchronous,并等待同步调用将成为多余的,最终将被折旧(否则你将不得不将它们定义在无处不在,就像asynchronous使得它真的毫无意义)。

这是一个简单的包装解决scheme:

 var fs = require('fs') function getFileRealPath(s){ try {return fs.realpathSync(s);} catch(e){return false;} } 

用法:

  • 适用于目录和文件
  • 如果item存在,则返回文件或目录的path
  • 如果item不存在,则返回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); } 

确保使用===运算符来testing返回值是否等于false。 fs.realpathSync()在适当的工作条件下将返回false是没有逻辑的原因,所以我认为这应该是100%。

我宁愿看到一个解决scheme,不会产生错误,并导致性能的影响。 从API的angular度来看,fs.exists()似乎是最优雅的解决scheme。