Check synchronously if file/directory exists in Node.js
如果文件或目录存在,如何使用node.js同步检查?
这个问题的答案多年来已经改变了。当前答案位于顶部,然后是多年来按时间顺序排列的各种答案:好的。当前答案
您可以使用
1 2 3 4 | const fs = require("fs"); // Or `import fs from"fs";` with ESM if (fs.existsSync(path)) { // Do something } |
它被弃用了好几年,但现在不再是了。来自文档:好的。
Note that
fs.exists() is deprecated, butfs.existsSync() is not. (The
callback parameter tofs.exists() accepts parameters that are
inconsistent with other Node.js callbacks.fs.existsSync() does not
use a callback.)Ok.
您特别要求进行同步检查,但是如果您可以使用异步检查(通常最好使用I/O),如果您使用的是
在
1 2 3 4 5 6 | try { await fs.promises.access("somefile"); // The check succeeded } catch (error) { // The check failed } |
或通过回拨:好的。
1 2 3 4 5 6 7 | fs.access("somefile", error => { if (!error) { // The check succeeded } catch (error) { // The check failed } }); |
历史答案
以下是按时间顺序排列的历史答案:好的。
- 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) ,但请注意,如果文件/目录不存在,则是一个错误;fs.stat 的文档建议如果需要检查是否存在而不打开,则使用fs.access ) - 2016年12月更新
fs.exists() 仍被否决,但fs.existsSync() 不再被否决。所以你现在可以安全地使用它。
2010年的原始答案:
您可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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) { // ... } |
…同样的,如果是一个文件,有
如果您不关心条目是什么并且只想知道它是否存在,您可以使用
1 2 3 4 | var path = require('path'); if (path.existsSync("/the/path")) { // or fs.existsSync // ... } |
它不需要使用
旁注:您明确要求如何同步检查,所以我使用了上述函数的
1 2 3 4 5 6 | // Is it a directory? lstat('/the/path', function(err, stats) { if (!err && stats.isDirectory()) { // Yes it is } }); |
但如果您需要同步版本,它就在那里。好的。2012年9月更新
下面几年前的答案现在有点过时了。当前的方法是使用
例子:好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 | var fs = require('fs'); if (fs.existsSync(path)) { // Do something } // Or fs.exists(path, function(exists) { if (exists) { // Do something } }); |
2015年2月更新
这里我们是在2015年,节点文档现在说EDOCX1(和
所以我们可能会回到各种各样的
不知道有多久了,但也有
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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月更新
您可以使用
1 2 3 | if (fs.existsSync(path)) { // Do something } |
它被弃用了好几年,但现在不再是了。来自文档:好的。
Note that
fs.exists() is deprecated, butfs.existsSync() is not. (The
callback parameter tofs.exists() accepts parameters that are
inconsistent with other Node.js callbacks.fs.existsSync() does not
use a callback.)Ok.
好啊。
从源代码来看,有一个同步版本的
请使用
使用当前推荐的(截至2015年)API(每个节点文档),这是我要做的:
1 2 3 4 5 6 7 8 9 10 11 12 13 | var fs = require('fs'); function fileExists(filePath) { try { return fs.statSync(filePath).isFile(); } catch (err) { return false; } } |
针对@broadband在评论中提出的eperm问题,提出了一个很好的观点。在许多情况下,fileexists()可能不是一个很好的方法来考虑这个问题,因为fileexists()不能保证布尔返回。您可以确定文件存在或不存在,但也可能会出现权限错误。权限错误不一定意味着文件存在,因为您可能对包含要检查的文件的目录缺少权限。当然,在检查文件是否存在时也有可能遇到其他错误。
所以我上面的代码实际上是doesfileexistendodiohaveaccesstoit(),但您的问题可能是doesfilenotexistandcouldicreateit(),这将是完全不同的逻辑(这将需要考虑eperm错误等)。
虽然fs.existssync答案直接解决了这里提出的问题,但这通常不是您想要的(您不只是想知道路径上是否存在"某物",您可能关心存在的"某物"是文件还是目录)。
底线是,如果您正在检查文件是否存在,那么您可能会这样做,因为您打算根据结果采取一些操作,并且该逻辑(检查和/或后续操作)应该适应这样的想法:在该路径上找到的某个东西可能是一个文件或目录,并且在检查的过程。
另一个更新
我自己也需要这个问题的答案,我查找了节点文档,似乎您不应该使用fs.exists,而是使用fs.open并使用输出的错误来检测文件是否不存在:
来自文档:
fs.exists() is an anachronism and exists only for historical reasons.
There should almost never be a reason to use it in your own code.In particular, checking if a file exists before opening it is an
anti-pattern that leaves you vulnerable to race conditions: another
process may remove the file between the calls to fs.exists() and
fs.open(). Just open the file and handle the error when it's not
there.
http://nodejs.org/api/fs.html fs fs exists path回调
我使用下面的函数来测试文件是否存在。它还捕获其他异常。因此,如果存在权利问题,如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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错误文档:
1 2 3 4 5 6 7 | { [Error: ENOENT: no such file or directory, stat 'X:\\delsdfsdf.txt'] errno: -4058, code: 'ENOENT', syscall: 'stat', path: 'X:\\delsdfsdf.txt' } |
例外情况:如果我们没有对该文件的权限,但存在:
1 2 3 4 5 6 7 | { [Error: EPERM: operation not permitted, stat 'X:\file.txt'] errno: -4048, code: 'EPERM', syscall: 'stat', path: 'X:\\file.txt' } |
这里的一些答案说,
Note that fs.exists() is deprecated, but fs.existsSync() is not. (The
callback parameter to fs.exists() accepts parameters that are
inconsistent with other Node.js callbacks. fs.existsSync() does not
use a callback.)
因此,您可以安全地使用fs.existssync()来同步检查文件是否存在。
fs.exists()已弃用,请不要使用它https://nodejs.org/api/fs.html fs exists path回调
您可以使用以下方法实现核心节点:https://github.com/node js/node-v0.x-archive/blob/master/lib/module.js_l86
1 2 3 4 5 6 | function statPath(path) { try { return fs.statSync(path); } catch (ex) {} return false; } |
这将返回stats对象,然后一旦您获得了可以尝试的stats对象
1 2 3 4 | var exist = statPath('/path/to/your/file.js'); if(exist && exist.isFile()) { // do something } |
我能想象的最快的事情是使用
我使用node进行线性自动化,所以我认为我共享了用于测试文件存在性的功能。
1 2 3 4 5 6 7 8 9 10 11 | 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; } |
使用文件系统(fs)测试将触发错误对象,然后需要用try/catch语句包装这些对象。节省一些精力,并使用0.4.x分支中介绍的功能。
1 2 3 4 5 6 7 8 9 10 | 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); }); }); |
下面是一个简单的包装解决方案:
1 2 3 4 | var fs = require('fs') function getFileRealPath(s){ try {return fs.realpathSync(s);} catch(e){return false;} } |
用途:
- 适用于目录和文件
- 如果项存在,则返回文件或目录的路径
- 如果项不存在,则返回false
例子:
1 2 3 4 5 6 | 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); } |
确保使用==运算符测试返回值是否等于false。在适当的工作条件下,fs.realpathsync()不会返回false,因此我认为这应该100%有效。
我希望看到的解决方案不会产生错误并导致性能下降。从API的角度来看,fs.exists()似乎是最优雅的解决方案。
从答案来看,似乎没有官方的API对此的支持(如直接和明确的检查)。许多答案都说要使用stat,但是它们并不严格。例如,我们不能假设stat抛出的任何错误都意味着某个东西不存在。
假设我们尝试不存在的东西:
1 2 | $ 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' } |
让我们尝试一些存在但我们无法访问的内容:
1 2 3 | $ 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' } |
至少你会想要:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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,以便它只同步写入,但异步运行。
这意味着您必须在顶层这样称呼它:
1 2 3 4 5 6 7 8 9 | (async () => { try { console.log(await dir_exists('god')); console.log(await dir_exists('fsm/appendage')); } catch(e) { console.log(e); } })(); |
另一种选择是使用.then和.catch来实现异步调用返回的承诺(如果需要进一步实现)。
如果您想检查某个东西是否存在,那么最好确保它是正确的类型,如目录或文件。示例中包含了这一点。如果不允许它是符号链接,则必须使用lstat而不是stat,因为stat将自动遍历链接。
您可以替换这里所有的异步来同步代码,并使用statsync代替。但是,一旦Async和Wait得到普遍支持,同步调用将成为多余的,最终会被贬低(否则,您必须在每个地方和链上定义它们,就像Async一样,使其真正没有意义)。
为那些"正确"的人更新了asnewr,指出它并没有直接回答问题,更多的是带来一个备选方案。
同步解决方案:Returns true if the path exists, false otherwise.
异步承诺解决方案
在异步上下文中,您可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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()上的文档。