如何使用node.js同步检查文件或目录是否存在?
exists
只会添加不必要的回调。
如何使用node.js同步检查文件或目录是否存在?
exists
只会添加不必要的回调。
Answers:
多年来,这个问题的答案已经改变。在目前的答案是在此间举行的顶部,然后用按时间顺序多年的各种答案:
您可以使用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.promises.access
则在使用async
函数时使用,否则fs.access
(由于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
} else {
// The check failed
}
});
以下是按时间顺序排列的历史答案:
stat
/ statSync
或lstat
/ lstatSync
)exists
/ existsSync
)exists
/ existsSync
,因此我们很可能回到stat
/ statSync
或lstat
/ lstatSync
)fs.access(path, fs.F_OK, function(){})
/ fs.accessSync(path, fs.F_OK)
,但请注意,如果文件/目录不存在,则是一个错误;如果您需要在不打开的情况下检查是否存在,则fs.stat
建议使用文档fs.access
)fs.exists()
仍不推荐使用,但fs.existsSync()
不再推荐使用。因此,您现在可以安全使用它。您可以使用statSync
或lstatSync
(文档链接),它为您提供一个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
;如果该条目根本不存在,则会引发错误。
如果您不在乎该条目是什么,而只想知道它是否存在,则可以使用user618408指出的path.existsSync
(或使用最新的fs.existsSync
):
var path = require('path');
if (path.existsSync("/the/path")) { // or fs.existsSync
// ...
}
它不需要a, try/catch
但不会为您提供任何有关事物的信息,只是它在那里。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
}
});
但是,如果您需要同步版本,则可以使用它。
以下几年前的答案现在有点过时了。当前的方法是用来fs.existsSync
对文件/目录是否存在进行同步检查(或者当然 fs.exists
要进行异步检查),而不是path
下面的版本。
例:
var fs = require('fs');
if (fs.existsSync(path)) {
// Do something
}
// Or
fs.exists(path, function(exists) {
if (exists) {
// Do something
}
});
现在我们到了2015年,Node文档现在说fs.existsSync
(和fs.exists
)“将被弃用”。(因为Node员工认为在打开某个东西之前先检查是否存在某种东西是愚蠢的;但这并不是检查某个东西是否存在的唯一原因!)
因此,我们可能会回到各种stat
方法...当然,除非/除非再次更改,否则。
不知道它已经存在多久了,但是也有fs.access(path, fs.F_OK, ...)
/fs.accessSync(path, 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
}
});
您可以使用fs.existsSync()
:
if (fs.existsSync(path)) {
// Do something
}
它已被弃用了几年,但现在已不再使用。从文档:
请注意,
fs.exists()
不建议使用,但fs.existsSync()
不建议使用。(用于fs.exists()
接受与其他Node.js回调不一致的参数的回调参数。fs.existsSync()
不使用回调。)
open
调用并处理异常,或者如果文件不是找到了。毕竟,现实世界是混乱的:如果先检查一下就可以了,但这并不意味着当您尝试打开它时它仍然会存在。如果您先检查却不存在,那并不意味着稍后不会存在。像这样的计时事情似乎很极端,但是它们总是出现。因此,如果您要打开,则没有必要先检查。
从源代码上看,有一个同步版本path.exists
- path.existsSync
。看起来文档中没有找到它。
path.exists
而path.existsSync
现在不推荐使用。请使用。fs.exists
和fs.existsSync
fs.exists
并且 已被弃用。改用fs.stat()或fs.access()。fs.existsSync
也
使用fs.existsSync
。它不被弃用。
https://nodejs.org/api/fs.html#fs_fs_existssync_path
fs.existsSync
。
fs.exists
为已弃用,而fs.existsSync
不是!
使用目前推荐的(截至2015年)API(根据Node docs),这是我的工作:
var fs = require('fs');
function fileExists(filePath)
{
try
{
return fs.statSync(filePath).isFile();
}
catch (err)
{
return false;
}
}
针对@broadband在评论中提出的EPERM问题,提出了一个很好的观点。在许多情况下,fileExists()可能不是考虑此问题的好方法,因为fileExists()不能真正保证布尔值返回。您可能可以确定文件是否存在,但是也可能会出现权限错误。权限错误并不一定意味着该文件存在,因为您可能缺少对包含要检查文件的目录的权限。当然,在检查文件是否存在时,您还有可能遇到其他错误。
因此,我上面的代码实际上是dosFileExistAndDoIHaveAccessToIt(),但您的问题可能是dosFileNotExistAndCouldICreateIt(),这将是完全不同的逻辑(这需要考虑EPERM错误)。
尽管fs.existsSync答案直接解决了此处提出的问题,但这通常不是您想要的(您不只是想知道路径中是否存在“某物”,您可能会关心“某物”是否存在)。存在的是文件或目录)。
最重要的是,如果您要检查文件是否存在,则可能要这样做,因为您打算根据结果采取一些措施,并且该逻辑(检查和/或后续措施)应符合该想法。在该路径上找到的东西可能是文件或目录,并且在检查过程中可能遇到EPERM或其他错误。
file.exists()
3%的用户没有简单的工具,而是迫使我们将其包装在try catch中吗?变得真实...今日的itch子。
另一个更新
我本人需要查找此节点文档,因此需要自己回答此问题,似乎您不应该使用fs.exists,而应使用fs.open并使用输出的错误来检测文件是否不存在:
从文档:
fs.exists()是过时的,仅出于历史原因存在。几乎永远没有理由在自己的代码中使用它。
特别是,在打开文件之前检查文件是否存在是一种反模式,使您容易受到竞争状况的影响:另一个过程可能会在调用fs.exists()和fs.open()之间删除该文件。只需打开文件并处理不存在的错误。
我使用下面的功能来测试文件是否存在。它也捕获其他异常。因此,如果存在权限问题,例如chmod ugo-rwx filename
Windows或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错误文档:
{
[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'
}
不建议使用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()的回调参数接受与其他Node.js回调不一致的参数。fs.existsSync()不使用回调。)
因此,您可以安全地使用fs.existsSync()来同步检查文件是否存在。
使用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);
});
});
如果您不打算操纵文件,则上面的文件fs.stat()
说要使用fs.access()
。它没有给出理由,是更快还是更少的内存使用?
我将节点用于线性自动化,因此我认为我可以共享用于测试文件是否存在的功能。
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.existsSync('filePath')
也可以在这里查看文档。
如果路径存在,则返回true,否则返回false。
在异步上下文中,您可以使用await
关键字以sync方法编写异步版本。您可以简单地将异步回调方法转换为如下的Promise:
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()上的文档。
function asyncFileExists(path) { //F_OK checks if file is visible, is default does no need to be specified. return new Promise(function (res, rej) { fs.access( path, fs.constants.F_OK, function (err) { err ? rej(err) : res(true); }, ); }); }
如果您想知道文件是否存在,则有可能需要它。
function getFile(path){
try{
return require(path);
}catch(e){
return false;
}
}
这是一个简单的包装解决方案:
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()似乎是最优雅的解决方案。
从答案中可以看出,对此没有官方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);
}
})();
另一种选择是,如果需要进一步调用,则对异步调用返回的promise使用.then和.catch。
如果要检查是否存在某些内容,那么最好也确保它是正确的类型,例如目录或文件。这包括在示例中。如果不允许使用符号链接,则必须使用lstat代替stat,因为stat将自动遍历链接。
您可以在此处替换所有异步来同步代码,而改用statSync。但是,请期望一旦异步和等待得到普遍支持,同步调用将最终变得多余,从而变得不受欢迎(否则,您将不得不在各处和整个链上进行定义,就像使用异步使它变得毫无意义一样)。