Node.js fs.writeFile() 清空文件

2023-12-06

我有一个更新方法,大约每 16-40 毫秒调用一次,里面有以下代码:

this.fs.writeFile("./data.json", JSON.stringify({
    totalPlayersOnline: this.totalPlayersOnline,
    previousDay: this.previousDay,
    gamesToday: this.gamesToday
}), function (err) {
    if (err) {
        return console.log(err);
    }
});

如果服务器抛出错误,“data.json”文件有时会变空。我该如何防止这种情况发生?


Problem

fs.writeFile不是原子操作。这是我将运行的示例程序strace on:

#!/usr/bin/env node
const { writeFile, } = require('fs');

// nodejs won’t exit until the Promise completes.
new Promise(function (resolve, reject) {
    writeFile('file.txt', 'content\n', function (err) {
        if (err) {
            reject(err);
        } else {
            resolve();
        }
    });
});

当我在下面运行时strace -f并整理输出以仅显示来自writeFile手术 (实际上跨越多个 IO 线程),我得到:

open("file.txt", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0666) = 9
pwrite(9, "content\n", 8, 0)            = 8
close(9)                                = 0

如你看到的,writeFile分三步完成。

  1. 该文件是open()编辑。这是一个原子操作,使用提供的标志,可以在磁盘上创建一个空文件,或者如果文件存在,则截断它。截断文件是确保只有您编写的内容最终出现在文件中的简单方法。如果文件中存在现有数据并且该文件是longer与您随后写入文件的数据相比,额外的数据将保留。为了避免这种情况,你需要截断。
  2. 内容已写好。因为我写了这么短的字符串,所以这是用一个单一的pwrite()调用,但对于大量数据,我认为 NodeJS 可能一次只会写入一个块。
  3. 手柄已关闭。

My strace每个步骤都发生在不同的节点 IO 线程上。这向我表明fs.writeFile()实际上可能会按照以下方式实施fs.open(), fs.write(), and fs.close()。因此,nodejs 不会在任何级别上将这种复杂的操作视为原子操作,因为事实并非如此。因此,如果您的节点进程终止(即使是正常终止)而不等待操作完成,则操作可能会执行上述任何步骤。在你的情况下,你会看到你的进程在之后退出writeFile()完成步骤 1 但在完成步骤 2 之前。

Solution

使用 POSIX 层以事务方式替换文件内容的常见模式是使用以下步骤:

  1. 将数据写入不同名称的文件,fsync()文件(请参阅“什么时候应该进行 fsync?”)“确保数据到达磁盘”), 进而close() it.
  2. rename()(或者,在 Windows 上,MoveFileEx() with MOVEFILE_REPLACE_EXISTING) 将与要替换的文件名称不同的文件替换。

使用此算法,无论程序何时终止,目标文件都会更新或不更新。而且,更好的是,日志式(现代)文件系统将确保,只要您fsync()在继续步骤 2 之前,先删除步骤 1 中的文件,这两个操作将按顺序发生。也就是说,如果您的程序执行步骤 1,然后执行步骤 2,但您拔掉了插头,那么当您启动时,您会发现文件系统处于以下状态之一:

  • 两个步骤均未完成。原始文件是完整的(或者如果它以前从未存在过,则它不存在)。替换文件不存在(步骤 1)writeFile()算法,open(),实际上从未成功),存在但空(步骤 1writeFile()算法已完成),或存在一些数据(步骤 2writeFile()算法部分完成)。
  • 第一步完成了。原始文件是完整的(或者如果之前不存在它仍然不存在)。替换文件包含您想要的所有数据。
  • 两个步骤都完成了。在原始文件的路径中,您现在可以访问所有替换数据,而不是空白文件。您在第一步中写入替换数据的路径不再存在。

使用此模式的代码可能如下所示:

const { writeFile, rename, } = require('fs');

function writeFileTransactional (path, content, cb) {
    // The replacement file must be in the same directory as the
    // destination because rename() does not work across device
    // boundaries.

    // This simple choice of replacement filename means that this
    // function must never be called concurrently with itself for the
    // same path value. Also, properly guarding against other
    // processes trying to use the same temporary path would make this
    // function more complicated. If that is a concern, a proper
    // temporary file strategy should be used. However, this
    // implementation ensures that any files left behind during an 
    // unclean termination will be cleaned up on a future run.
    let temporaryPath = `${path}.new`;
    writeFile(temporaryPath, content, function (err) {
        if (err) {
            return cb(err);
        }

        rename(temporaryPath, path, cb);
    });
};

这基本上与您在任何语言/框架中针对相同问题使用的解决方案相同。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Node.js fs.writeFile() 清空文件 的相关文章

  • JavaScript 中的埃拉托斯特尼筛法对大量数据无限运行

    我一直在尝试写埃拉托斯特尼筛法 http en wikipedia org wiki Sieve of EratosthenesJavaScript 中的算法 基本上我只是按照以下步骤操作 创建从 2 到 n 1 的连续整数列表 令第一个素
  • 使用 Android 发送 HTTP Post 请求

    我一直在尝试从 SO 和其他网站上的大量示例中学习 但我无法弄清楚为什么我编写的示例不起作用 我正在构建一个小型概念验证应用程序 它可以识别语音并将其 文本 作为 POST 请求发送到 node js 服务器 我已确认语音识别有效 并且服务
  • Three.js:缩放几何图形后错误的 BoundingBox

    在我的场景中 我有一个简单的立方体 var test new THREE Mesh new THREE CubeGeometry 10 10 10 new THREE MeshBasicMaterial scene add test 该立方
  • 使用 JavaScript 禁用第三方 cookie

    我正在努力根据所有在欧盟运营的公司的数据保护规则实施新的 Cookie 政策合规性 根据该规则 用户在使用任何网站时必须能够拒绝 接受除必需的 Cookie 之外的所有内容 在我客户的网站中 我可以看到正在存储以下第三方 cookie ga
  • 如何使用javascript将大图像转换为十六进制?

    如果我尝试将图像转换为十六进制 无论我使用哪个函数 我都会收到此错误消息 该图像的大小为 7 MB 19812 毫秒 清理 1401 2 1455 0 gt 1401 2 1455 0 MB 9 9 0 ms 自上次 GC 以来 8 3 m
  • 图像无法在带有 DOM 的 IE 中加载:控制台中的 7009 错误(无法解码)

    当在 IE 中的单个页面上加载许多图像时 在 IE11 中重现 其中一些图像开始加载失败 并在控制台中出现类似以下警告的内容 DOM7009 无法解码 URL 处的图像 某些唯一的 url 当我查看网络流量时 似乎确实从服务器收到了每个图像
  • 可以在初始 DOM 解析期间/之前修改 DOM 吗?

    是否可以在初始 DOM 解析期间或之前修改 DOM 或者我是否必须等到 DOM 被解析和构建之后才能与其交互 更具体地说 是否有可能阻止 DOM 中的脚本元素使用用户脚本 内容脚本或 Chrome 或 Firefox 中的类似脚本运行 在解
  • 引导程序提前输入未填充承诺的响应

    我的引导程序预输入如下
  • 如何将函数附加到弹出窗口关闭事件(Twitter Bootstrap)

    我做了一些搜索 但我只能认为我可以将事件附加到导致其关闭的按钮 https stackoverflow com questions 13205103 attach event handler to button in twitter boo
  • Chrome 扩展程序在代码中使用 client_secret

    我正在开发具有自己的 oAuth 授权的 Google Chrome 扩展 当然 我必须使用 client id 和 client secret 作为请求令牌 有什么办法可以向用户隐藏这些数据吗 由于此请求只是 javascript 源代码
  • 使用 CSS 或 Javascript 填充动画

    我只是想知道是否可以使用 CSS 或 javascript 创建填充动画 基本上我想创建一个填充动画 如下图所示 http i40 tinypic com eit6ia png http i40 tinypic com eit6ia png
  • Javascript split 不是一个函数

    嘿朋友们 我正在使用 javascript sdk 通过 jQuery facebook 多朋友选择器在用户朋友墙上发布信息 但是我收到此错误friendId split 不是函数 这是我的代码 function recommendToFr
  • window.location 和 location.href 之间的区别

    我对之间的区别感到困惑window location and location href 两者似乎都以相同的方式行事 有什么不同 window location是一个对象 它保存有关当前文档位置的所有信息 主机 href 端口 协议等 lo
  • DataTables row.add 到特定索引

    我正在替换这样的行项目 var targetRow entity row dataTable targetRow closest table dataTable DataTable dataTable row targetRow remov
  • 可以设置标题样式吗? (并且使用CSS或js?)[重复]

    这个问题在这里已经有答案了 我想知道是否可以设计一个title a href title This is a title Hello a 样式问题有两个方面 文本格式 编码 我猜这是可能的 所以在问题中这样做 工具提示样式 你能把它弄大一点
  • Firebase 函数 onWrite 未被调用

    我正在尝试使用 Firebase 函数实现一个触发器 该触发器会复制数据库中的一些数据 我想观看所有添加的内容votes user vote 结构为 我尝试的代码是 const functions require firebase func
  • 使用 Vue 的多模式组件

    我在 Vue 中实现动态模式组件时遇到问题 A common approach I follow to display a set of data fetched from the db is I dump each of the rows
  • 带参数的事件监听器

    我想将参数传递给 JavaScript 中的事件侦听器 我已经找到了解决方案 但我无法理解它们为什么或如何工作以及为什么其他解决方案不起作用 我有 C C 背景 但是 Javascript 函数的执行有很大不同 您能否帮助我理解以下示例如何
  • JavaScript 相对路径

    在第一个 html 文件中 我使用了一个变量类别链接 var categoryLinks Career prospects http localhost Landa DirectManagers 511 HelenaChechik Dim0
  • 如何在react-highcharts中使用图表工具提示格式化程序?

    如何使用图表工具提示格式化程序 我正在使用高图表的反应包装器 我有这样的配置 const CHART CONFIG tooltip formatter tooltip gt var s b this x b each this points

随机推荐

  • 将 C 语言转换为 PHP 的 CRC16 函数

    我需要帮助将 C 代码转换为 PHP 以下是C代码 static const U16 crctab16 0x0000 0x1189 U16 GetCrc16 const U8 pData int nLength U16 fcs 0xffff
  • 我的 BIOS 设置中没有启用 Hyper-V 的选项

    我是 Windows Phone 8 应用程序开发新手 我安装了SDK 8 0 当我运行应用程序时 它显示一条错误 告诉我启用 Hyper V 在搜索过程中我发现这个 MSDN 文档BIOS 中有解决方案 但是当进入我的BIOS设置时 却没
  • docker容器启动后运行命令

    我准备了一个 docker compose 文件来部署带有数据库的容器 services tmp db image microsoft mssql server linux latest environment ACCEPT EULA Y
  • AngularJS ng-route 如何在解析时发出http请求

    我有一个简单的模板 带有输入和锚链接 按下它后 将加载另一个模板 我希望第二个模板通过 http 请求获取信息 我默认使用 ng route 重定向到搜索模板 并从路径 search title 重定向到结果模板 并且我尝试在加载结果模板之
  • 服务器中的 zend 框架部署

    我有一个服务器 我在其中上传了 zend 框架中的工作 在子域中 文件夹名称是 访问 所以 当我去 http mysitename com visit 它显示了一个目录结构 Parent Directory application docs
  • flutter setstate 只重建一个孩子

    在flutter中我需要当我调用setstate时 它只重建一个小部件 我将 2 个孩子放在一堆中 我需要当按下按钮时 只重建第二个孩子 bool popup false Scaffold appBar AppBar title const
  • Docker 命名卷位置 Mac

    我正在使用 Docker for Mac 1 12 1 并有一个启动 WordPress 和 MySQL 服务的 Docker Compose 文件 撰写文件 version 2 services db container name mys
  • Sparklyr 分割字符串(到字符串)

    尝试在 Sparklyr 中拆分字符串 然后将其用于连接 过滤 我尝试了建议的方法 将字符串标记化 然后将其分隔为新列 这是一个可重现的示例 请注意 我必须将在 copy to 之后变成字符串 NA 的 NA 转换为实际的 NA 有没有办法
  • 将 Windows 批处理文件变量设置为星期几

    我有一个每天运行的 Windows 批处理文件 希望将数据记录到文件中并希望轮换它 即最多包含最近 7 天的数据 查看了命令DATE and DELIMS 无法找出解决方案 是否有一个简单的解决方案来创建包含星期几的文件名 即 0 表示星期
  • JavaFX 进度条不更新

    我已经搜索了与此相关的所有其他问题 但没有运气 我已经尝试不同的事情四个多小时了 但完全没有任何进展 或错误 这更令人沮丧 所以我想我最终会在这里问 我正在开发一款小型生存游戏作为业余项目 以自学更多有关 Java UI 元素的知识 玩家寻
  • Clearcase:集成流合并的活动依赖项(补丁)

    我们有一个补丁模型 我们打算使用cset pl findmerge
  • 正则表达式乘法

    在我询问之前 我环顾了一段时间 但我似乎找到了很多如何使用正则表达式进行电子邮件和货币转换的方法 但没有找到关于将数字与设定值相乘的方法 本质上 我有一个货币值字段 127 25GBP 需要转换为 165 42 只有两位小数 没有货币指示器
  • 如何进行多线程以更快地将图像加载到tableView?

    我将图像加载到 tableView 每次功能 UITableViewCell tableView UITableView tableView cellForRowAtIndexPath NSIndexPath indexPath 执行后 会
  • 制作尺寸相似的二维数组数组时出现意外行为

    MWE def showArrayOfList a b c wlist np zeros szNext szThis for szThis szNext in a b b b b b b c print wlist map np shape
  • python 中的多个 IF 语句

    我正在尝试打印特定单元格中的内容 我知道在将内容提取到输出之前要检查的单元格 我为此使用多个 IF 语句 if lineCount 5 if line 0 print line 0 A5 OPfound 1 break if line 1
  • 如何在查询集中包含外键的详细信息字段(django 和rest_api)

    我在 django 中使用rest api来显示 聊天 的查询集 我尝试了一段时间 但没有成功 在 angularjs 控制器中 我调用一个执行以下操作的函数 scope conversations http get api chats t
  • 在 Jenkins 2 Pipeline 脚本中使用任意插件

    使用片段生成器Jenkins 2 中的工具 我可以像在作业中一样设置一个插件 然后它会生成我可以在管道脚本中使用的 Groovy 但是 如果我感兴趣的插件未在 示例步骤 下拉列表中列出怎么办 片段生成器 如何确定如何创建脚本块来检测我想要使
  • 有什么办法可以在 DAO 和 MS Access 中拥有长文本(备忘录)参数吗?

    我已经搜索了所有这方面的信息 似乎 Access 中的 DAO 参数限制为 255 个字符 真的吗 仍然 即使在 Office 2010 中 这似乎很荒谬 我不想切换到 ADO 但目前看来我必须这样做 有没有办法在仍然使用 DAO 和 VB
  • 带纹理的 JSONLoader

    我在 Blender 中制作了一个带有纹理的形状并将其导出 然后用 json loader 显示它 几乎一切都很好 几何形状很好 你可以在形状上看到纹理 但没有颜色 只是黑色和白色 如何显示纹理颜色 我做错了什么 json文件 metada
  • Node.js fs.writeFile() 清空文件

    我有一个更新方法 大约每 16 40 毫秒调用一次 里面有以下代码 this fs writeFile data json JSON stringify totalPlayersOnline this totalPlayersOnline