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

如何使用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已过时 ) 如果不:

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

历史答案

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

  • 2010 年的原始答案
    stat / statSynclstat / lstatSync
  • 2012 年 9 月更新
    exists / 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()不再被弃用。因此,您现在可以安全使用它。

2010 年的原始答案:

您可以使用statSynclstatSync文档链接 ),这将为您提供fs.Stats对象 。通常,如果功能的同步版本可用,则其名称将与带有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 指出的 path.existsSync (或使用最新的fs.existsSync ):

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

但是,如果您需要同步版本,则可以使用它。

2012 年 9 月更新

以下几年前的答案现在有点过时了。当前的方法是使用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 年 2 月更新

现在我们到了 2015 年,Node 文档现在说fs.existsSync (和fs.exists )“将被弃用”。 (因为 Node 员工认为在打开某个东西之前先检查是否存在某种东西是愚蠢的;但这并不是检查某个东西是否存在的唯一原因!)

因此,我们可能会回到各种stat方法... 当然,除非 / 除非再次更改,否则。

2015 年 12 月更新

不知道已经在那里fs.access(path, fs.F_OK, ...)了多久了,但是还有fs.access(path, fs.F_OK, ...) / fs.accessSync(path, fs.F_OK) 。并且至少从 2016 年 10 月起, fs.stat文档建议使用fs.access进行存在性检查( 建议fs.access检查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
    }
});

2016 年 12 月更新

您可以使用fs.existsSync()

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

它已被弃用了几年,但现在已不再使用。从文档:

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

从源头看,有一个path.exists - path.existsSync的同步版本。看起来文档中没有找到它。

更新:

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

2016 年更新:

fs.exists fs.existsSync 已弃用 。改用fs.stat()fs.access()

更新 2019:

使用fs.existsSync 。它不被弃用。 https://nodejs.org/api/fs.html#fs_fs_existssync_path

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

另一个更新

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

从文档:

fs.exists()是过时的,仅出于历史原因存在。几乎永远没有理由在自己的代码中使用它。

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

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

我使用下面的功能来测试文件是否存在。它还捕获其他异常。因此,如果存在权限问题,例如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, ...
  }
}

异常输出,如果文件不存在,则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.existsfs.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);
  });
});

如果您不打算操作fs.stat()上的文档, 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;
}