对于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时间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时间17: 00'的命令时 整个dndinfo. json文件都被替换成了:
"17:00"
我知道这是因为我使用了fs.writeFile 但我不知道如何只指定 "时间 "并更新?
没有实用的方法来更新文件中的一段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 sending message');
throw e; // make sure caller can see the message
}
}
而不是写 JSON.stringify(editMessage, null, 2)
到你的JSON中,你可能要先编辑它的内容。
你可以将文件的内容替换为 data.replace()
的方法。
你可以参考这个答案,了解全部内容。https:/stackoverflow.coma141811364865314。
由于文件的工作方式,你可以改变的唯一方式是 部分 的方法是用完全相同大小的东西来替换它的内容。 此外,你的文件系统可能是以8K块写入磁盘控制器的,所以除了非常特殊的情况外,没有必要这样做。
除了重写整个文件,你还需要考虑如果文件变短了,或者机器上有其他进程同时对文件进行读取(或写入!),会发生什么情况。
对于这类问题,一个非常常见的通用解决方案是将新文件写入同一目录下的新文件名,并在旧文件上重命名。 这意味着其他进程读取你的文件时,要么得到新文件,要么得到旧文件,这几乎都是比 "一半一半 "的解决方案更可取。
有趣的是,这个问题今天出现了,因为我今天早些时候正好写了这个例程,为我的调试器存储REPL历史。 如果你想阅读一个完整的[但经过轻微测试的]实现,请看一下
https:/github.comwesgarlandniimblobcfb64356c4e5a9394ba2e2b0e82b2f3bf2ba0305libniim.js#L373。和https:/github.comwesgarlandniimblobcfb64356c4e5a9394ba2e2b0e82b2f3bf2ba0305libniim.js#L459。
这些都太大了,不适合做堆栈溢出评论,但我已经提供了一个静态链接到文件的特定版本,它应该可以持续几年。