【问题标题】:node js: does fs.rename overwrite file if already exists节点 js:如果已经存在 fs.rename 是否覆盖文件
【发布时间】:2014-01-19 15:56:17
【问题描述】:

如果文件已经存在,fs.rename 会覆盖它吗?

var fs = require('fs'),
    oldPath = 'firstfile.txt',
    newPath = 'temp/firstfile.txt';

fs.rename(oldPath, newPath, function (err) {
    console.log('rename callback ', err); 
});

如果 '/newFolder/somefile.txt' 区域存在会发生什么?

【问题讨论】:

  • 我不断收到错误:ENOENT, rename 'c:\test\firstfile.txt'

标签: node.js file-io


【解决方案1】:

简短回答:


长答案:

我创建了一个脚本来检查它:

var fs = require('fs');

创建两个文件:

fs.writeFileSync('a.txt',"This is a file")
fs.writeFileSync('b.txt',"This is another file")

重命名:

fs.renameSync('a.txt','b.txt');

检查它是否被覆盖:

var text = fs.readFileSync('b.txt', "utf-8");

console.log(text) // This is a file

【讨论】:

  • 10 倍。有没有办法防止这种情况发生?
  • 我想我必须做 fs.exists(file, function(exists) { if (exists) { return; } else { fs.rename(... ?
  • 我猜你是对的。您可以尝试找到一个抽象它的模块。
  • rename() 在 Windows 上通常不会这样做,但它似乎对 node 这样做。为什么/记录在哪里?
【解决方案2】:

nodejs 的 fs.rename() 覆盖文件,因为这就是 Unix rename() 的定义方式,fs.rename() 被记录为包装 rename() Unix 系统调用。我不知道 nodejs 文档中有任何地方直接说明了有关fs.rename() 的内容。但是,有几点需要注意,我们可以确定这一点:

  1. nodejs 文档链接到rename(2) 的 Linux 手册页 when describing the functionality of fs.rename。文档的 GitHub 永久链接没有链接它,但处理器会自动将 rename(2) 转换为 rename(2)

  2. “Syscalls and man pages” section of documentation 声明系统调用在 Windows 上模拟 unix 行为。我从“有时无法在 Windows 上替换 Unix 系统调用语义”这句话推断出这一点,这意味着 nodejs 在可能的情况下已经在 Windows 上实现了 Unix 语义

    大多数 Unix 系统调用具有 Windows 等效项,但相对于 Linux 和 macOS,Windows 上的行为可能有所不同。有关有时无法在 Windows 上替换 Unix 系统调用语义的微妙方式的示例,请参阅Node issue 4760

  3. 我看到过其他关于此类事情的讨论,人们总是提到 nodejs 是如何使用 libuv 的,所以应该只看 libuv。 libuv 的目标是提供 POSIX API 的可移植异步实现,因此它的目标之一是即使在 Windows 上也能像 unix 一样运行。 libuv 文档似乎没有详细讨论rename(),但the Windows implementation of fs__rename() 调用MoveFileEx() with MOVEFILE_REPLACE_EXISTING

  4. 哦,我差点忘了。即使你知道 nodejs 将 fs.rename() 定义为 POSIX rename(),也许你不知道 POSIX-defined behavior of rename() 关于覆盖:

    如果由 new 参数命名的链接存在,则应将其删除并将 old 重命名为 new。在这种情况下,一个名为 new 的链接在整个重命名操作期间对其他线程保持可见,并引用 newold引用的文件> 手术开始之前。

简单地说,如果重命名的目标已经存在,这描述了一个事务性文件替换。如果在调用rename() 之前已经存在具有新名称的文件,则它永远不会停止存在——即使您的程序崩溃或盒子断电。在某个时间点,新名称将开始引用具有旧名称的文件。

您应该更喜欢这种方法,而不是删除原始文件,然后重命名新创建的文件,因为新路径下的文件将暂时不存在(可能导致试图打开它的东西出现竞争条件),或者,如果进程被终止或在正确的时间永久发生电源故障。

注意:由于可移植性问题,当您希望您的代码也适用于 Windows 用户时,最好考虑使用像 graceful-fscross-spawn 这样的可移植性助手。我意识到这不是提问者的问题,但我推断提问者只会问这样的问题,因为 win32 背景中重命名无法覆盖文件,或者因为只有在对 Unix 以外的可移植性感兴趣时才会问这样的问题.

【讨论】:

    【解决方案3】:

    看起来函数 fs.rename() 提供的功能与 Linux rename(2) 命令提供的功能相同(来源:Move File in ExpressJS/NodeJS)。话虽如此,如果您查看 Linux rename(2) 命令的文档,他们会说如果您要重命名的文件名已经存在,则现有文件名将被替换并覆盖(来源:http://linux.die.net/man/2/rename

    【讨论】:

      猜你喜欢
      • 2017-10-29
      • 2015-05-10
      • 2015-06-18
      • 1970-01-01
      • 1970-01-01
      • 2019-08-21
      • 1970-01-01
      • 2015-03-10
      • 2021-02-10
      相关资源
      最近更新 更多