NodeJS 使用fs修改json文件的一个部分,而不是覆盖整个文件

t2a7ltrp  于 2023-03-01  发布在  Node.js
关注(0)|答案(3)|浏览(194)

对于Discord机器人,我目前有一个命令,显示我们的DnD会话的信息:


.
数据存储在一个dndinfo.json文件中,如下所示:

{"time":"**18:00 UK time**",
"date":"**14/05/20**",
"dm":"**Mannion**",
"prime":"Playing",
"smurphy":"Playing",
"calle":"Playing",
"smardon":"Playing",
"james":"Playing",
"mannion":"DMing",
"dex":"Playing",
"module":"Hoard of the Dragon Queen"}

我希望用户能够执行命令,如"! te time 17:00",它将相应地更新时间。
我目前正在使用此代码:

const Discord = module.require('discord.js');
const fs = require('fs');
const dndinfo = require ('../../dndinfo.json');

module.exports = {
    name: 'test',
    aliases: ['te'],
    category: 'dnd',
    description: 'Updates DnD info',
    usage: '!te',
    run: async (client, message, args) => {

        const time = dndinfo.time;
        let editMessage = message.content.slice(9);

        if (message.content.toLowerCase().includes('time')) {

            fs.readFile('dndinfo.json', function(err, data) {
                console.log(time);
                fs.writeFile('dndinfo.json', JSON.stringify(editMessage, null, 2), (err) => {
                    if (err) console.error;
                    message.channel.send ('message written');

                });
            });
        }
    },
};

当我运行命令'! te time 17:00'时,整个dndinfo.json文件被替换为:

"17:00"

我知道这是因为我使用的是fs.writeFile,但我不知道如何指定只有'时间',并已更新?

hsvhsicv

hsvhsicv1#

更新文件中的一段JSON是不可行的,只是格式的类型或磁盘上的布局使其不可行。
更新文件中内容的常用机制是写出整个JSON结构,并将修改后的内容替换为新内容。如果您还没有完成此操作所需的所有内容,则可以先读入文件的内容,进行修改,然后再将其写出。
这里有一个函数,它读入JSON,将JSON解析为一个Javascript对象,修改该对象,转换回JSON并将其写出。

const fsp = require('fs').promises;

async function udpateTimeInFile(time) {
    try {
        let data = await fsp.readFile('dndinfo.json');
        let obj = JSON.parse(data);

        // set whatever property or properties in the object that you are trying to change
        obj.time = time;

        await fsp.writeFile('dndinfo.json', JSON.stringify(obj));
        message.channel.send('message written');
     } catch(e) {
        // error handling here
        console.log(e); 
        message.channel.send('error writing new data');
        throw e;      // make sure caller can see the message
     }
}
xlpyo6sf

xlpyo6sf2#

与其将JSON.stringify(editMessage, null, 2)写入JSON,不如先编辑它的内容。
您可以使用data.replace()方法替换文件的内容。
您可以参考以下答案了解全部覆盖范围:https://stackoverflow.com/a/14181136/4865314

jslywgbw

jslywgbw3#

由于文件的工作方式,你可以改变一个文件的 * 部分 * 的唯一方法是用完全相同大小的东西替换它的内容。另外,你的文件系统可能以8K块写入磁盘控制器,所以没有/point/来做这件事,除非在非常特殊的情况下。
除了重写整个文件之外,您还需要考虑如果文件变短,或者计算机上有其他进程同时读取(或写入!)该文件会发生什么。
对于这类问题,一个非常常见的解决方案是将新文件写入同一目录中的新文件名,并在旧文件名的基础上重命名它。这意味着读取文件的其他进程将获得新文件或旧文件,这几乎总是比"一半一半"的解决方案更可取。
有趣的是,这个问题今天出现了,因为我碰巧在今天早些时候编写了这个例程,为我的调试器存储REPL历史。如果您想通读一个完整的(但经过简单测试的)实现,请查看
https://github.com/wesgarland/niim/blob/cfb64356c4e5a9394ba2e2b0e82b2f3bf2ba0305/lib/niim.js#L373 and https://github.com/wesgarland/niim/blob/cfb64356c4e5a9394ba2e2b0e82b2f3bf2ba0305/lib/niim.js#L459
这些对于堆栈溢出注解来说太大了,但是我提供了一个指向文件特定版本的静态链接,它应该可以持续几年。

相关问题