Node.js修改JSON文件时如何保持程序内状态与文件内容同步?
问题原因与解决方案
第一个问题:require加载JSON后文件更新但变量值不变
核心原因有两点:
require()是Node.js的模块加载机制,加载的模块会被全局缓存,第一次执行require('./dataWrite.json')拿到内容后,后续只要进程不重启,不管磁盘上的文件怎么改,再次require同一路径拿到的永远是第一次缓存的内容,不会重新读取磁盘。- 你调用的
fs.readFile是异步非阻塞API,发起调用后不会等待文件读写完成,会直接往下执行后面的console.log("after",dt),这时候写入操作甚至还没执行完,dt自然还是旧值。
解决方法
不要用require()加载需要动态更新的JSON文件,每次要获取最新内容时,都用fs的读文件API主动读取磁盘文件,同时要把读取最新值的逻辑放在写入完成的回调中,或者用async/await保证执行顺序。
修正后的参考代码:
const fs = require('fs/promises'); // 使用promise版本的fs更方便控制执行顺序 async function updateJson() { // 读取修改前的内容 let dt = JSON.parse(await fs.readFile('./dataWrite.json', 'utf8')); console.log("before", dt); // 读取源文件、写入目标文件 const sourceData = await fs.readFile('./data.json', 'utf8'); await fs.writeFile('./dataWrite.json', sourceData); // 写入完成后重新读取磁盘上的最新值 dt = JSON.parse(await fs.readFile('./dataWrite.json', 'utf8')); console.log("after", dt); } updateJson().catch(err => console.error(err));
如果一定要用require加载,可以在每次文件写入完成后手动清除require缓存,下次require时就会重新加载文件,但不推荐这种方式,随意打乱模块缓存机制容易引发不可预期的问题:
delete require.cache[require.resolve('./dataWrite.json')] const newDt = require('./dataWrite.json')
附带问题:代码不修改目标文件的原因
核心问题是混淆了同步API和异步API的用法:
fs.readFileSync是同步方法,返回值就是读取到的文件内容,本身不接收回调函数作为参数,你传入的回调函数会被直接忽略,永远不会执行。- 你把写入文件的逻辑写在了
fs.readFileSync传入的回调里,因为同步API根本不会执行回调,自然走不到writeFileSync的逻辑,文件当然不会被修改。 - 同步API如果执行出错会直接抛出异常,不需要在回调中处理err字段。
修正后的参考代码
const fs = require('fs'); // 同步读取直接接收返回值,不需要传回调 let dt = fs.readFileSync('./dataTest.json', 'utf8'); console.log('before', dt); // 同步读取源文件 const data = fs.readFileSync('./data.json', 'utf8'); // 同步写入目标文件 fs.writeFileSync('./dataTest.json', data); console.log('data', data); // 重新读取修改后的最新值 dt = fs.readFileSync('./dataTest.json', 'utf8'); console.log("after", dt);
如果要使用异步写法,就不要调用带Sync后缀的同步API,换成fs.readFile、fs.writeFile,按执行顺序把逻辑写在回调中即可,也可以搭配async/await简化写法。
内容的提问来源于stack exchange,提问作者Vayun
相关产品推荐
相关产品推荐

