在Electron中通过Angular读写本地JSON文件及CRUD实现方案咨询
哈哈,我太懂这种每次启动项目还要额外开个服务的麻烦了!给你几个实用的解决方案,既能摆脱手动启动json-server的繁琐,又能搞定fs相关的问题:
这个方案完美适配你之前的使用习惯,不用手动开服务,代码里集成自动启动:
首先确保已经安装了json-server:
npm install json-server --save-dev
然后在Electron的主进程(比如main.js)里添加启动逻辑:
const { app } = require('electron'); const childProcess = require('child_process'); const path = require('path'); let jsonServerProcess; app.whenReady().then(() => { // 自动启动json-server,指定你的JSON文件路径 jsonServerProcess = childProcess.spawn('npx', [ 'json-server', '--watch', path.join(__dirname, 'db.json'), // 替换成你的本地JSON文件路径 '--port', '3000' // 自定义端口,避免冲突 ]); // 可选:打印服务日志,方便排查问题 jsonServerProcess.stdout.on('data', (data) => { console.log(`json-server日志: ${data}`); }); jsonServerProcess.stderr.on('data', (data) => { console.error(`json-server错误: ${data}`); }); }); // 关闭Electron时记得杀掉json-server进程,避免残留 app.on('before-quit', () => { if (jsonServerProcess) { jsonServerProcess.kill(); } });
这样启动Electron的同时,json-server就自动跑起来了,完全不用手动操作。
你遇到的fs问题大概率是路径配置或者Electron安全限制导致的,按以下步骤排查:
确保渲染进程有Node.js权限
如果是在渲染进程里调用electron-json-storage,需要在主进程创建窗口时配置webPreferences:const { BrowserWindow } = require('electron'); const path = require('path'); function createWindow() { const mainWindow = new BrowserWindow({ webPreferences: { // 推荐用preload脚本(更安全),替代直接开nodeIntegration preload: path.join(__dirname, 'preload.js'), contextIsolation: true // 保持开启,符合Electron安全规范 } }); }通过preload脚本暴露存储API
在preload.js里封装electron-json-storage的方法,暴露给渲染进程:const { contextBridge } = require('electron'); const storage = require('electron-json-storage'); contextBridge.exposeInMainWorld('electronStorage', { get: (key) => storage.get(key), set: (key, data) => storage.set(key, data), // 手动实现put逻辑:先获取原有数据再合并更新 put: (key, updateData) => { return storage.get(key).then(existingData => { const mergedData = { ...existingData, ...updateData }; return storage.set(key, mergedData); }); } });之后在渲染进程里就可以安全调用:
window.electronStorage.get('user').then(data => console.log(data));检查存储路径权限
electron-json-storage默认存在用户的应用数据目录(比如Windows的C:\Users\[用户名]\AppData\Roaming\[你的应用名]),这个路径是有权限的,如果你自定义了存储路径,要确保路径不是系统保护文件夹。
不用第三方库,自己封装get/post/put逻辑,灵活又轻量:
创建一个storage.js工具文件:
const fs = require('fs').promises; const path = require('path'); // 定义JSON文件存储路径,比如项目根目录的data文件夹 const dbPath = path.join(__dirname, 'data', 'db.json'); // 确保存储目录存在 async function ensureDirExists() { const dir = path.dirname(dbPath); try { await fs.access(dir); } catch { await fs.mkdir(dir, { recursive: true }); } } // Get:读取整个文件或指定键 async function get(key) { await ensureDirExists(); try { const rawData = await fs.readFile(dbPath, 'utf8'); const jsonData = JSON.parse(rawData); return key ? jsonData[key] : jsonData; } catch { // 文件不存在时返回默认值 return key ? undefined : {}; } } // Post:添加新数据(比如向数组中push) async function post(key, newItem) { await ensureDirExists(); const currentData = await get(); if (!Array.isArray(currentData[key])) { currentData[key] = []; } currentData[key].push(newItem); await fs.writeFile(dbPath, JSON.stringify(currentData, null, 2)); return newItem; } // Put:更新指定ID的数据 async function put(key, itemId, updatedData) { await ensureDirExists(); const currentData = await get(); if (!Array.isArray(currentData[key])) { throw new Error(`键${key}对应的数据不是数组`); } const targetIndex = currentData[key].findIndex(item => item.id === itemId); if (targetIndex === -1) { throw new Error(`ID为${itemId}的数据不存在`); } currentData[key][targetIndex] = { ...currentData[key][targetIndex], ...updatedData }; await fs.writeFile(dbPath, JSON.stringify(currentData, null, 2)); return currentData[key][targetIndex]; } module.exports = { get, post, put };
之后在主进程或渲染进程(通过preload暴露)里导入使用即可,完全不需要额外服务。
这个库比electron-json-storage更活跃,API更简洁,自动处理了路径和权限问题:
首先安装:
npm install electron-store
在主进程里使用:
const Store = require('electron-store'); const store = new Store({ name: 'my-app-db' // 自定义存储文件名 }); // Get const user = store.get('user'); // Post(新增或替换) store.set('user', { name: 'Jim', age: 30 }); // Put(合并更新) store.set('user', { age: 31 }, { merge: true }); // 复杂场景:更新数组中的指定项 function updateItemInArray(key, itemId, updates) { const array = store.get(key, []); const targetIndex = array.findIndex(item => item.id === itemId); if (targetIndex !== -1) { array[targetIndex] = { ...array[targetIndex], ...updates }; store.set(key, array); return array[targetIndex]; } throw new Error('数据不存在'); }
同样可以通过preload脚本暴露给渲染进程使用。
内容的提问来源于stack exchange,提问作者Jim

