如何使用node.js同步检查文件或目录是否存在?
多年来,这个问题的答案发生了变化。目前的答案在顶部,然后是按时间顺序的多年来的各种答案:
你可以使用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
(如果不是)(因为fs.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
} catch (error) {
// 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
(docs link),它会给你一个fs.Stats
object。通常,如果函数的同步版本可用,它将与异步版本具有相同的名称,最后使用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
;如果条目根本不存在则抛出错误。
如果您不关心条目是什么,只想知道它是否存在,您可以使用path.existsSync
(或使用最新的,fs.existsSync
)作为noted by user618408:
var path = require('path');
if (path.existsSync("/the/path")) { // or fs.existsSync
// ...
}
它不需要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
)“将被弃用”。 (因为节点的人认为在打开它之前检查是否存在某些东西是愚蠢的,它是什么;但这不是检查某些东西是否存在的唯一原因!)
因此,我们可能会回到各种stat
方法......当然,除非这种情况再次发生变化。
不知道它有多久,但也有fs.access(path, fs.F_OK, ...)
/ fs.accessSync(path, fs.F_OK)
。至少截至2016年10月,fs.stat
documentation建议使用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()
不使用回调。)
如果你不打算操纵文件,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;
}
这是一个简单的包装解决方案:
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);
}
})();
另一种方法是使用.then和.catch对异步调用返回的promise进行进一步调用。
如果要检查是否存在某些内容,那么最好还是确保它是正确的类型,例如目录或文件。这包含在示例中。如果不允许使用符号链接,则必须使用lstat而不是stat,因为stat将自动遍历链接。
您可以在此处替换所有异步同步代码,而是使用statSync。然而,一旦异步和等待变得普遍支持,同步调用将变得多余,最终会被折旧(否则你将不得不在各处定义它们,就像异步一样使它变得毫无意义)。
更新的答案为那些人'正确'指出它不直接回答问题,更多带来另一种选择。
fs.existsSync('filePath')
也see docs here。
如果路径存在则返回true,否则返回false。
在异步上下文中,您可以使用await
关键字在同步方法中编写异步版本。您可以简单地将异步回调方法转换为这样的承诺:
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');
}
}
the docs访问()。
看看源代码,有一个同步版本的path.exists
- path.existsSync
。看起来它在文档中被遗漏了。
path.exists
和path.existsSync
现已弃用。
请使用fs.exists
和fs.existsSync
。
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()实际上不能保证布尔返回。您可能确定该文件存在或不存在,但您可能还会收到权限错误。权限错误并不一定意味着文件存在,因为您可能缺少包含要检查的文件的目录的权限。当然,在检查文件存在时,您可能会遇到其他错误。
所以我上面的代码实际上是doFileExistAndDoIHaveAccessToIt(),但你的问题可能是doFileNotExistAndCouldICreateIt(),这将是完全不同的逻辑(需要考虑EPERM错误等)。
虽然fs.existsSync的答案直接解决了这里提出的问题,但通常不会是你想要的(你不只是想知道路径上是否存在“某事”),你可能会关心“事物”是否存在存在的是文件或目录)。
最重要的是,如果您正在检查文件是否存在,那么您可能正在这样做,因为您打算根据结果采取某些操作,并且该逻辑(检查和/或后续操作)应该适应这个想法在该路径中找到的东西可能是文件或目录,并且您在检查过程中可能会遇到EPERM或其他错误。
另一个更新
需要自己查找这个问题的答案我查找了节点文档,似乎你不应该使用fs.exists,而是使用fs.open并使用输出错误来检测文件是否不存在:
来自文档:
fs.exists()是一种时代错误,只是出于历史原因而存在。几乎没有理由在你自己的代码中使用它。
特别是,在打开文件之前检查文件是否存在是一种反模式,使您容易受到竞争条件的影响:另一个进程可能会在调用fs.exists()和fs.open()之间删除该文件。只需打开文件并在错误处理时处理错误。
我使用下面的函数来测试文件是否存在。它还捕获了其他例外情况。因此,如果存在权利问题,例如chmod ugo-rwx filename
或在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, ...
}
}
异常输出,case文件中的nodejs errors documentation不存在:
{
[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()来同步检查文件是否存在。
path
模块不提供path.exists
的同步版本,所以你必须使用fs
模块。
我能想象的最快的事情是使用fs.realpathSync
会抛出你必须捕获的错误,所以你需要使用try / catch创建自己的包装函数。
使用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);
});
});