NodeJs:fs.stat() 或 fs.access() 检查文件夹是不是存在?

Posted

技术标签:

【中文标题】NodeJs:fs.stat() 或 fs.access() 检查文件夹是不是存在?【英文标题】: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),但是有没有关于不超过两年的“最佳实践”的官方信息?

【问题讨论】:

【参考方案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。

【讨论】:

以上是关于NodeJs:fs.stat() 或 fs.access() 检查文件夹是不是存在?的主要内容,如果未能解决你的问题,请参考以下文章

NodeJs异步的执行过程

NodeJS fs.open 在现有文件上失败(不是路径问题)

nodejs实现文件的拷贝复制

nodejs之fs模块

nodejs - fs模块 - 文件操作

nodejs 遍历目录