Node.js:检测到一个文件,用 fs.createWriteStream() 打开,被删除

Posted

技术标签:

【中文标题】Node.js:检测到一个文件,用 fs.createWriteStream() 打开,被删除【英文标题】:Node.js: Detecting a file, opened with fs.createWriteStream(), becoming deleted 【发布时间】:2013-10-18 13:09:02 【问题描述】:

假设我有以下 Node 程序,一台机器会“Ping!”:

var machine = require('fs').createWriteStream('machine.log', 
    flags    : 'a',
    encoding : 'utf8',
    mode     : 0644
);

setInterval(function () 
    var message = 'Ping!';
    console.log(message);
    machine.write(message + '\n');
, 1000);

每秒,它将向控制台打印一条消息,并将其附加到日志文件中(如果需要,它将在启动时创建)。这一切都很好。

但是现在,如果我在进程运行时删除machine.log 文件,它会继续愉快地嗡嗡作响,但写入将不再成功,因为文件已消失。但看起来写入会默默地失败,这意味着我需要明确检查这种情况。我搜索了Stream docs,但似乎找不到在发生此类事情时发出的明显事件。 write()的返回值也没有用。

如何检测我正在写入的文件何时被删除,以便我可以尝试重新打开或重新创建该文件?这是一个 CentOS 盒子,如果相关的话。

【问题讨论】:

【参考方案1】:

写入实际上并没有失败。

当您删除在另一个程序中打开的文件时,您正在删除指向该文件 inode 的命名链接。打开它的程序仍然指向那个inode。它会很高兴地继续写入它,实际上是写入磁盘。只是现在没有办法查看它,因为你删除了对它的命名引用。 (如果有其他参考,例如硬链接,您仍然可以!)。

这就是为什么期望他们的日志文件“消失”的程序(比如logrotate 的 b/c)通常支持一个信号(通常是SIGHUP,有时是SIGUSR1),告诉他们关闭他们的文件(在它真的消失了,因为现在任何地方都没有指向它的链接)并重新创建它。

你也应该考虑这样的事情。

【讨论】:

啊,有道理。我以前见过这种情况,但我从来没有想过这是同样的行为。我想知道如果一个更严重的问题使文件实际上不可写(磁盘故障等)会发生什么——节点进程会收到通知还是整个事情都会崩溃? 底层操作系统将让节点进程使用适当的errno。这是否会从节点的 io 层一直到 Stream 类,然后一直到应用程序,我不确定。我假设它会。 from doc: SIGUSR1 被 Node.js 保留用于启动调试器。可以安装监听器,但这样做可能会干扰调试器。 或使用fsPromises.watch 或chokidar 多平台包装器 或者使用fsPromises.writeFile,它比流式传输要慢,但对文件删除很健壮。

以上是关于Node.js:检测到一个文件,用 fs.createWriteStream() 打开,被删除的主要内容,如果未能解决你的问题,请参考以下文章

如何从 node.js 应用程序检测损坏/不完整的 MP3 文件?

为啥 Heroku 无法检测到 Node.js buildpack?

Docker“检测到未定义的 Node.js 版本”

Socket.io (Node.js) 未检测到连接的 QTcpSocket

WASM 中的环境检测:Web、Node.js 还是独立运行时?

如何在 Node.js 中读取符号链接