同步检查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
/statSync
或lstat
/lstatSync
) - 2012年9月更新
(exists
/existsSync
) - 2015年2月更新
(注意exists
/existsSync
即将弃用,所以我们可能会回到stat
/statSync
或lstat
/lstatSync
) - 2015年12月更新
(还有fs.access(path, fs.F_OK, function(){})
/fs.accessSync(path, fs.F_OK)
,但是请注意,如果文件/目录不存在,则是错误; docs forfs.stat
build议使用fs.access
如果你需要检查存在而不打开) - 2016年12月更新
fs.exists()
仍然被弃用,但fs.existsSync()
不再被弃用。 所以你现在可以安全地使用它。
2010年的原始答案:
你可以使用statSync
或lstatSync
( docs link ),它给你一个fs.Stats
对象 。 一般情况下,如果某个函数的同步版本可用,则它将与具有Sync
的asynchronous版本具有相同的名称。 所以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
指出的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.exists
– path.existsSync
。 看起来像在文档中错过了。
更新:
现在不推荐使用 path.exists
和path.existsSync
。 请使用 。 fs.exists
和fs.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()之间删除文件。 只要打开文件并在不存在的情况下处理错误。
我使用下面的函数来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.exists
和fs.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。