【问题标题】:Using fs.stat and fs.writeFile使用 fs.stat 和 fs.writeFile
【发布时间】:2017-08-27 01:49:55
【问题描述】:

我需要在执行fs.writeFile 之前检查文件是否存在,所以如果文件已经存在,fs.writeFile 不会替换该文件。但是文档说明了以下内容:

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

如果我直接调用fs.writeFile,函数会替换已经存在的文件,而error变量将是null

如果文件已经存在,我想忽略对fs.writeFile 的调用。

谢谢。

【问题讨论】:

    标签: node.js fs


    【解决方案1】:

    如果文件已经存在,我想忽略对fs.writeFile 的调用。

    使用wx 标志(记录在here):

    wx - 与 'w' 类似,但如果路径存在则失败。

    fs.writeFile('/path/to/file', data, { flag : 'wx' }, function(err) {
      if (err && err.code === 'EEXIST') {
        console.log('file already exists, not overwriting');
        return;
      }
      ...
    })
    

    编辑:不建议在fs.open/fs.writeFile/fs.readFile 之前使用fs.stat 的原因是由于固有的竞争条件:在调用fs.stat 和(比如)fs.writeFile 之间,虽然在调用fs.stat 时该文件还不存在,但可以 创建文件的时间窗口很小。所以fs.writeFile 仍有可能覆盖现有文件。

    如果您使用文件标志,则自动检查是否存在。

    【讨论】:

      【解决方案2】:

      罗伯特有正确的答案(只需传入适当的标志fs.writeFile(fname, data, { flag : 'wx' }, ...)),但我想我会解释为什么不建议使用fs.stat() 后跟fs.writeFile()。当你做这样的事情时:

      fs.stat(fname, function(err) {
          if (err) {
             // in the bit of time right here, there is a race condition
             fs.writeFile(fname, data, function(err) {
                 // file written
             });
          }
      });
      

      存在竞争条件。在任何类型的多进程系统或与其他系统共享的任何类型的文件系统中,可能存在fs.stat() 报告文件不存在的情况,但在那个时刻和您实际调用fs.writeFile() 的时间之间,其他一些进程或线程或计算机写入该文件,现在您刚刚覆盖了一个您不想做的现有文件。因此,这在某些情况下根本不可靠,因此不推荐。

      您需要的是一个原子操作,它会检查它是否存在,如果不存在,则会为您创建它。这将为您提供一个可靠的系统,使文件永远不会被意外覆盖。

      通过将wx 标志传递给fs.writeFile(),您告诉底层操作系统仅当文件不存在时才将这些字节写入文件,并且它将以原子方式完成,没有多重-线程/进程/计算机竞争条件。


      竞态条件是有限制的,并且在某些情况下您的系统实际上不会受到它的影响(只有一个 node.js 进程可以写入该文件),但始终编码更安全无论如何,安全的方式,事实上,安全的方式也是更少的代码。

      【讨论】:

      • 我想我们都觉得这值得更多解释:D
      • @robertklep - 是的,在 cmets 中提到的 OP 他们不理解原因,而您的答案(我赞成)在我写这篇文章时没有包含该解释。
      • 是的,我也意识到指出为什么不推荐这样做是件好事:)
      • @hdunn - 您似乎不了解两个 api 调用之间可能发生的竞争条件。
      • @jfriend00 - 好的,你的解释很好,我错了,删除我之前的评论。谢谢你让我重新思考,干杯。
      猜你喜欢
      • 2020-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-11
      相关资源
      最近更新 更多