Node.js脚本中JSON.stringify偶现数组畸形:分隔符被替换为闭方括号
问题分析与解决方案
核心问题:异步写文件的竞态条件
你代码里每找到一个匹配项就触发一次异步写文件操作,fs.writeFile是异步执行的,当多个写操作同时发起时,后一个操作可能在前一个操作还没完全写完文件时就开始写入,导致文件内容被错误拼接,最终出现你看到的畸形JSON——比如前一次写入的闭合方括号没被覆盖,后一次写入的内容直接追加在后面。
次要问题:代码逻辑的其他疏漏
splitMD函数里的&是位运算符号,应该改为逻辑与&&,否则逻辑判断会失效。file != {}这个判断毫无意义,file是字符串类型,永远不会等于空对象。- 使用
line.find(element => { extractions(element, file); })是错误的:find需要回调返回布尔值,且只会遍历到第一个返回true的元素就停止。你实际需要遍历所有行并检查匹配,应该用line.forEach(element => { extractions(element, file); })。 - 未拼接完整文件路径:
fs.readdirSync返回的是文件名,直接用fs.readFileSync(file)会在当前工作目录找文件,而不是目标目录,会导致找不到文件的问题。
修复后的代码
const fs = require('fs'); const path = require('path'); const devPath = '/home/user/directory'; const activeReminder = []; function buildArray() { let getFiles = fs.readdirSync(devPath); getFiles.forEach(file => { splitMD(file); }); // 所有文件遍历完成后,一次性写入JSON buildReminderJSON(); } function splitMD(file) { if (path.extname(file) === ".md") { // 拼接完整文件路径 const fullFilePath = path.join(devPath, file); let data = fs.readFileSync(fullFilePath, 'utf8'); const lines = data.split(/\r?\n/); // 改用forEach遍历所有行,处理所有匹配项 lines.forEach(element => { extractions(element, file); }); } }; function extractions(element, file) { if (element.includes("- [ ] reminder: ")) { const datedReminder = "- [ ] [["+file+"]]" + element.split('- [ ] reminder:')[1]; activeReminder.push(datedReminder); } } // 修正函数名,和调用保持一致 function buildReminderJSON() { const reminderJSON = JSON.stringify(activeReminder); // 改用同步写文件,彻底避免异步竞态(数据量不大时无性能影响) try { fs.writeFileSync("reminder.json", reminderJSON, 'utf8'); console.log("JSON文件写入成功"); } catch (err) { console.log("Error while writing reminder JSON:"); console.log(err); } } buildArray(); module.exports = { buildArray };
额外说明
- 把写文件操作移到所有遍历完成后执行,确保只写入一次,彻底解决竞态问题。如果坚持用异步写,也只需调用一次
fs.writeFile即可,无需循环触发。 - 补充了完整文件路径的拼接,解决了潜在的文件找不到问题。
内容的提问来源于stack exchange,提问作者AFK
相关产品推荐
相关产品推荐

