任何花了时间编写
Node
的人都有可能使用了文件系统模块。此核心模块中有一个方法与其他所有方法都不同,据大多数专家说,尽管它在许多其他开发人员中很受欢迎,但根本没有人使用。因此该方法已被弃用多年。当然,我谈论的是fs.exists(和fs.existsSync)。
对于一些人来说,这是一个非常有争议的问题--比如看这个问题或这一个。弃用它的原因是,与所有其他文件系统方法不同,它不使用规范的
nodeback API
。此外,它的主要用例场景(在打开之前检查文件是否存在)实际上是一种反模式,应通过尝试打开该文件并可能处理该错误来替代它。
但是,尽管它已经存在了很长时间,但仍然有大量的人继续使用fs.exists
,并且某些新手或相对新手肯定对应该使用什么感到困惑。至少我自己第一次使用时也遇到这个问题。
尽管我同意该方法通常是多余的,有时甚至是完全没有意义的(在可能发生一些特殊情况并且可能在此期间将其删除的情况下,在对该文件执行某些操作之前检查文件是否有帮助),但我确信许多人会合理使用此方法,如果它被设计的足够好。
因此,如果您正在寻找fs.exists(Sync)
的替代品,请继续阅读下面的内容,这是关于如何在不使用(这个不建议使用的方法)的情况下检查文件或目录是否存在的简短讨论。
Synchronous exists
建议同步操作文件系统绝非我本人,但是它更简单了,所以让我们先从这里简单的内容开始。
官方fs
文档建议改为使用fs.statSync
或fs.accessSync
,因此让我们一起来研究一下。
fs.accessSync
此方法检查文件的可访问性,而仅检查其可访问性。如果无法访问该文件,它将引发错误;如果可以访问,它将完全不执行任何操作。
因此,假设您要在尝试创建myDir
目录之前检查是否存在,/path/to/myDir
表示其目录:
try {
fs.accessSync(myDir);
} catch (e) {
fs.mkdirSync(myDir);
}
或者,如果您更喜欢重新创建,用来代替fs.existsSync
:
function fsExistsSync(myDir) {
try {
fs.accessSync(myDir);
return true;
} catch (e) {
return false;
}
}
if (!fsExists(myDir)) {
fs.mkdirSync(myDir);
}
fs.statSync
上面的代码有一个问题:如果myDir
存在,但不是目录而是恰好具有相同名称的文件,该怎么办?在这种情况下,该路径将是可访问的,但它不是文件夹,并且您可能最终会在讨厌的调试中大吼大叫,之后的其他原因也因此而导致失败。
解决方案是使用fs.statSync
和isDirectory
或isFile
方法返回的变量stats
。这是一个同步函数,用于检查给定路径是否存在以及是否为目录:
function isDirSync(aPath) {
try {
return fs.statSync(aPath).isDirectory();
} catch (e) {
if (e.code === 'ENOENT') {
return false;
} else {
throw e;
}
}
}
if (!isDirSync(myDir)) {
fs.mkdirSync(myDir);
}
isDirSync
方法为如果给定路径存在且为目录返回true
,其他所有情况下将返回false
。请注意如果遇到其他错误,它也会引发错误。实际上这不是必需的,因为据我所知,确实没有其他可能的错误,但是,你也许永远不知道!
该ENOENT
错误码表示fs.statSync
抛出一个‘no such file or directory’
错误。您需要检查这一点,因为与您期望的不同,检查不存在的路径的统计信息不会返回空stats
对象,而是会导致函数失败并引发该错误。
您有时可能还会看到人们检查错误号而不是错误码。最好不要这样做,因为根据运行的Node
版本或运行的操作系统的不同,错误号可能会有所不同。
Asynchronous exists
在异步世界中,可以使用fs.access
或fs.stat
替代fs.exists
,开始看看吧。
fs.access
根据nodeback API
,fs.access
中的回调函数的第一个参数是错误对象,让我们再次检查目录是否已经存在并且创建它;
fs.access(myDir, function(err) {
if (err && err.code === 'ENOENT') {
fs.mkdir(myDir);
}
});
请注意,我将检查错误和代码结合在一起。此特定解决方案的替代方法是先尝试使用fs.mkdir
,如果目录已存在时将抛出错误码EEXIST
。
fs.stat
当然,我们还可以检查路径的统计信息,并根据结果决定要执行的操作。例如,让我们创建一个异步checkIfFile
函数,该函数仅在给定路径存在且为文件的情况下返回true
,而在所有其他情况下返回false
:
function checkIfFile(file, cb) {
fs.stat(file, function(err, stats) {
if (err) {
if (err.code === 'ENOENT') {
return cb(null, false);
} else {
return cb(err);
}
}
return cb(null, stats.isFile());
});
}
checkIfFile(aPath, function(err, isFile) {
if (isFile) {
// handle the file
}
});
或者,使用Promise
:
function checkIfFile(file) {
return new Promise(function(resolve, reject) {
return fs.stat(file).then(function(stats) {
resolve(stats.isFile());
}).catch(function(err) {
if (err.code === 'ENOENT') {
resolve(false);
} else {
reject(err);
}
});
});
}
checkIfFile(aPath).then(function(isFile) {
if (isFile) {
// handle the file
}
}).catch(function(e) { throw e; });
所有做这些的目的不是要停留在完美替代fs.exists
的细节上,而是要表明您可以使用比fs.exists
更好的方法,而不是使用(不建议使用的方法)来实现您原本的目标。
但是我真的想要 fs.exists !!!
如果你想的话,可以继续使用!只需编写您自己的替换文件来代替fs.exists
,或者引用社区里其他用户创建的。这个库是个很好的选择,不过您也可以随便挑选!
后记
这篇文章翻译于这里,也是我第一篇翻译的关于node的技术文章,是因为最近频繁的使用文件系统相关API,无意间看到这篇有点趣味性的原文,今天有点时间就翻译了一下,哈哈?