同步检查Node.js中是否存在文件/目录

问题描述 投票:1012回答:13

如何使用node.js同步检查文件或目录是否存在?

node.js
13个回答
2003
投票

多年来,这个问题的答案发生了变化。目前的答案在顶部,然后是按时间顺序的多年来的各种答案:

目前的答案

你可以使用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
    }
});

历史答案

以下是按时间顺序排列的历史答案:

  • 2010年的原始答案 (stat / statSynclstat / lstatSync
  • 2012年9月更新 (exists / existsSync
  • 2015年2月更新 (注意到exists / existsSync即将弃用,所以我们可能会回到stat / statSynclstat / 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()不再被弃用。所以你现在可以安全地使用它。

Original answer from 2010:

你可以使用statSynclstatSyncdocs link),它会给你一个fs.Stats object。通常,如果函数的同步版本可用,它将与异步版本具有相同的名称,最后使用Sync。所以statSyncstat的同步版本; lstatSynclstat等的同步版本。

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
    }
});

但是如果你需要同步版本,它就在那里。

Update September 2012

几年前的答案现在有点过时了。目前的方法是使用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
    }
});

Update February 2015

在这里,我们在2015年,Node文档现在说fs.existsSync(和fs.exists)“将被弃用”。 (因为节点的人认为在打开它之前检查是否存在某些东西是愚蠢的,它是什么;但这不是检查某些东西是否存在的唯一原因!)

因此,我们可能会回到各种stat方法......当然,除非这种情况再次发生变化。

Update December 2015

不知道它有多久,但也有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
    }
});

Update December 2016

你可以使用fs.existsSync()

if (fs.existsSync(path)) {
    // Do something
}

它被弃用了几年,但不再是。来自文档:

请注意,fs.exists()已被弃用,但fs.existsSync()不是。 (fs.exists()的回调参数接受与其他Node.js回调不一致的参数.fs.existsSync()不使用回调。)


0
投票

如果你不打算操纵文件,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;
}

-1
投票

这是一个简单的包装解决方案:

var fs = require('fs')
function getFileRealPath(s){
    try {return fs.realpathSync(s);} catch(e){return false;}
}

用法:

  • 适用于目录和文件
  • 如果item存在,则返回文件或目录的路径
  • 如果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);
}

确保使用===运算符来测试return是否等于false。 fs.realpathSync()在正常工作条件下返回false是没有逻辑的原因所以我认为这应该100%工作。

我希望看到一个不会产生错误并导致性能下降的解决方案。从API的角度来看,fs.exists()似乎是最优雅的解决方案。


-2
投票

从答案中可以看出,没有正式的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。然而,一旦异步和等待变得普遍支持,同步调用将变得多余,最终会被折旧(否则你将不得不在各处定义它们,就像异步一样使它变得毫无意义)。


-2
投票

更新的答案为那些人'正确'指出它不直接回答问题,更多带来另一种选择。

Sync solution:

fs.existsSync('filePath')see docs here

如果路径存在则返回true,否则返回false。

Async Promise solution

在异步上下文中,您可以使用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访问()。


118
投票

看看源代码,有一个同步版本的path.exists - path.existsSync。看起来它在文档中被遗漏了。

Update:

path.existspath.existsSync现已弃用。 请使用fs.existsfs.existsSync

Update 2016:

fs.existsfs.existsSync也被弃用了。请改用fs.stat()fs.access()


53
投票

使用当前推荐的(截至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或其他错误。


20
投票

另一个更新

需要自己查找这个问题的答案我查找了节点文档,似乎你不应该使用fs.exists,而是使用fs.open并使用输出错误来检测文件是否不存在:

来自文档:

fs.exists()是一种时代错误,只是出于历史原因而存在。几乎没有理由在你自己的代码中使用它。

特别是,在打开文件之前检查文件是否存在是一种反模式,使您容易受到竞争条件的影响:另一个进程可能会在调用fs.exists()和fs.open()之间删除该文件。只需打开文件并在错误处理时处理错误。

http://nodejs.org/api/fs.html#fs_fs_exists_path_callback


11
投票

我使用下面的函数来测试文件是否存在。它还捕获了其他例外情况。因此,如果存在权利问题,例如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'
}

5
投票

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
}

4
投票

这里的一些答案说fs.existsfs.existsSync都被弃用了。根据文档,这不再是真实的。现在只有fs.exists被解雇了:

请注意,不推荐使用fs.exists(),但不推荐使用fs.existsSync()。 (fs.exists()的回调参数接受与其他Node.js回调不一致的参数.fs.existsSync()不使用回调。)

因此,您可以安全地使用fs.existsSync()来同步检查文件是否存在。


2
投票

path模块不提供path.exists的同步版本,所以你必须使用fs模块。

我能想象的最快的事情是使用fs.realpathSync会抛出你必须捕获的错误,所以你需要使用try / catch创建自己的包装函数。


0
投票

使用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);
  });
});
© www.soinside.com 2019 - 2024. All rights reserved.