【问题标题】:NodeJs: fs.stat() or fs.access() to check if a folder exists?NodeJs:fs.stat() 或 fs.access() 检查文件夹是否存在?
【发布时间】:2019-06-28 02:30:06
【问题描述】:

我目前正在尝试找出“正确”的方法来检查本地文件夹是否存在,然后再将文件保存到其中,并且对 nodejs 文档有点困惑。

fs.exists() 已弃用,您应该使用 fs.stat() 或 fs.access()。到目前为止一切顺利。

fs.stat():

不建议在调用 fs.open()、fs.readFile() 或 fs.writeFile() 之前使用 fs.stat() 检查文件是否存在。相反,用户代码应该直接打开/读取/写入文件并处理文件不可用时引发的错误。

这表明,我应该尝试编写,捕获错误,创建文件夹,然后再试一次。我也很好,即使我正在移动/重命名文件,所以我不直接使用上述三个功能之一。

然后,医生说:

要检查文件是否存在而不进行后续操作,建议使用 fs.access()。

由于我并没有真正修改文件,而是“仅”修改了它的内容,因此有人可能会争辩说这是要走的路。

但话又说回来,fs.access() 文档也详细说明了为什么这是一个坏主意:

不建议在调用 fs.open()、fs.readFile() 或 fs.writeFile() 之前使用 fs.access() 检查文件的可访问性。这样做会引入竞争条件,因为其他进程可能会在两次调用之间更改文件的状态。相反,用户代码应该直接打开/读取/写入文件并处理文件不可访问时引发的错误。

Yadda yadda yadda,已经有一些相关的问题(here,或here),但是有没有关于不超过两年的“最佳实践”的官方信息?

【问题讨论】:

    标签: node.js fs


    【解决方案1】:

    您可以通过existsSync()轻松同步。

    但如果你想异步执行,就这样做吧:

    await fs.promises.access("path");
    

    或者把它放在这样的try-catch中......

    try {
         await fs.promises.access("path");
        // The check succeeded
    } catch (error) {
        // The check failed
    }
    

    【讨论】:

      【解决方案2】:

      我猜文档建议使用 fs.access 在之后没有操作时检查文件是否存在,因为它是一个较低级别且简单的 API,其唯一目的是检查文件访问元数据(包括文件是否存在或不)。就性能而言,更简单的 API 也可能会更好一些,因为它可能只是到底层本机代码的直接映射。(注意:我没有做任何基准测试,请用grain 我的声明盐)。

      fs.statfs.access 相比提供了更高级别的抽象。它返回文件访问之外的信息。

      import {promises as fs} from "fs";
      import * as oldfs from "fs";
      
      (async function() {
          // fs.stat has higher level abstraction
          const stat = await fs.stat(__dirname);
          console.log(stat.isDirectory());
          console.log(stat.isFile());
          console.log(stat.ctime);
          console.log(stat.size);
      
          try {
              // fs.access is low level API, it throws error when it doesn't match any of the flags
              // is dir exists? writable? readable?
              await fs.access(__dirname, oldfs.constants.F_OK | oldfs.constants.W_OK | oldfs.constants.R_OK);
          } catch (error) {
              console.log(`${__dirname} is not exists / writable / readable`);
          }
      })();
      
      

      【讨论】:

      • 注意await fs.stat抛出 ENOENT 异常。
      • 这是一个完整的辅助函数,仅用于检查目录是否存在且可写。我宁愿在 NodeJS 中使用现成的东西来代替它。
      【解决方案3】:

      我认为该文档是不言自明的。

      如果您只想检查文件是否存在 - 之后不尝试打开/读取/写入文件,您应该使用访问权限:

      // Check if the file exists in the current directory, and if it is writable.
      fs.access(file, fs.constants.F_OK | fs.constants.W_OK, (err) => {
        if (err) {
          console.error(
            `${file} ${err.code === 'ENOENT' ? 'does not exist' : 'is read-only'}`);
        } else {
          console.log(`${file} exists, and it is writable`);
        }
      });
      

      如果你想打开/读/写文件,你不应该调用access来检查是否存在,而是直接做你的操作并自己处理错误:

      //write (NOT RECOMMENDED)
      
      fs.access('myfile', (err) => {
        if (!err) {
          console.error('myfile already exists');
          return;
        }
      
        fs.open('myfile', 'wx', (err, fd) => {
          if (err) throw err;
          writeMyData(fd);
        });
      });
      
      //write (RECOMMENDED)
      
      fs.open('myfile', 'wx', (err, fd) => {
        if (err) {
          if (err.code === 'EEXIST') {
            console.error('myfile already exists');
            return;
          }
      
          throw err;
        }
      
        writeMyData(fd);
      });
      

      这些示例来自您链接的文档。

      如果您在启动时进行简单检查,您也可以使用未弃用的existsSync() - 如果您在循环中或多次使用它,请避免,因为这会阻塞 nodejs 事件循环。

      【讨论】:

      • 感谢您的回答,但正如我的帖子中所述,我不是要检查文件本身是否存在,而是要检查父文件夹是否存在,以便我可以将文件保存到其中。因此,从技术上讲,我不打算修改文件夹本身,而只是修改它的内容。
      • @BenSower 很好,如文档中所述,除非您尝试使用openwriteread,否则您应该使用access。在您的情况下,您没有打开文件夹,也没有读取文件夹,也没有写入文件夹(您正在编写 file 而不是文件夹本身)。最坏的情况你可以使用existsSync()
      • 感谢@HRK44,最后我在引导过程中改用了 existsSync()。
      【解决方案4】:

      虽然我认为node不支持,但正确的方法是打开目录获取dirfd。那就是只应该使用 open 然后在 dirfd 或 fd 上调用 faccess 或 fstat。 然后,如果目录打开成功,则使用 openat 和 dirfd 打开文件。

      我编写了一个使用 fs.createReadStream 的 http 服务器,并在路径不是文件时处理错误。它还使用了 pause 和 resume 以便能够在流开始传输到响应之前对打开的文件使用 fstat。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-05
        • 2013-03-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多