本地存储 #
一、存储方案概述 #
1.1 存储方案对比 #
| 方案 | 容量 | 同步/异步 | 适用场景 |
|---|---|---|---|
| localStorage | ~5MB | 同步 | 简单键值对 |
| sessionStorage | ~5MB | 同步 | 临时会话数据 |
| IndexedDB | 大量 | 异步 | 结构化数据 |
| electron-store | 无限制 | 同步/异步 | 应用配置 |
| 文件系统 | 无限制 | 异步 | 大文件存储 |
1.2 存储位置 #
javascript
const { app } = require('electron');
// 用户数据目录
console.log('用户数据:', app.getPath('userData'));
// Windows: C:\Users\<user>\AppData\Roaming\<appName>
// macOS: ~/Library/Application Support/<appName>
// Linux: ~/.config/<appName>
// 应用数据目录
console.log('应用数据:', app.getPath('appData'));
// 临时目录
console.log('临时目录:', app.getPath('temp'));
二、Web 存储 API #
2.1 localStorage #
javascript
// 渲染进程中使用
// 存储
localStorage.setItem('username', 'John');
localStorage.setItem('settings', JSON.stringify({ theme: 'dark' }));
// 读取
const username = localStorage.getItem('username');
const settings = JSON.parse(localStorage.getItem('settings'));
// 删除
localStorage.removeItem('username');
// 清空
localStorage.clear();
// 监听变化
window.addEventListener('storage', (e) => {
console.log('Key:', e.key);
console.log('Old:', e.oldValue);
console.log('New:', e.newValue);
});
2.2 sessionStorage #
javascript
// 会话级存储,窗口关闭后清除
// 存储
sessionStorage.setItem('tempData', 'value');
// 读取
const tempData = sessionStorage.getItem('tempData');
// 删除
sessionStorage.removeItem('tempData');
// 清空
sessionStorage.clear();
2.3 存储封装 #
javascript
// storage.js
class Storage {
constructor(prefix = 'app_') {
this.prefix = prefix;
}
getKey(key) {
return this.prefix + key;
}
set(key, value) {
localStorage.setItem(this.getKey(key), JSON.stringify(value));
}
get(key, defaultValue = null) {
const value = localStorage.getItem(this.getKey(key));
return value ? JSON.parse(value) : defaultValue;
}
remove(key) {
localStorage.removeItem(this.getKey(key));
}
clear() {
const keys = Object.keys(localStorage);
keys.forEach(key => {
if (key.startsWith(this.prefix)) {
localStorage.removeItem(key);
}
});
}
}
const storage = new Storage();
module.exports = storage;
三、IndexedDB #
3.1 基本使用 #
javascript
// 打开数据库
const request = indexedDB.open('MyDatabase', 1);
request.onerror = (event) => {
console.error('数据库打开失败');
};
request.onsuccess = (event) => {
const db = event.target.result;
console.log('数据库打开成功');
};
// 创建对象存储
request.onupgradeneeded = (event) => {
const db = event.target.result;
// 创建用户存储
const userStore = db.createObjectStore('users', { keyPath: 'id' });
userStore.createIndex('name', 'name', { unique: false });
userStore.createIndex('email', 'email', { unique: true });
};
3.2 CRUD 操作 #
javascript
class IndexedDBHelper {
constructor(dbName, version) {
this.dbName = dbName;
this.version = version;
this.db = null;
}
async init() {
return new Promise((resolve, reject) => {
const request = indexedDB.open(this.dbName, this.version);
request.onerror = () => reject(request.error);
request.onsuccess = () => {
this.db = request.result;
resolve(this.db);
};
request.onupgradeneeded = (event) => {
this.onUpgrade(event.target.result);
};
});
}
onUpgrade(db) {
// 子类实现
}
async add(storeName, data) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], 'readwrite');
const store = transaction.objectStore(storeName);
const request = store.add(data);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
async get(storeName, key) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], 'readonly');
const store = transaction.objectStore(storeName);
const request = store.get(key);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
async getAll(storeName) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], 'readonly');
const store = transaction.objectStore(storeName);
const request = store.getAll();
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
async put(storeName, data) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], 'readwrite');
const store = transaction.objectStore(storeName);
const request = store.put(data);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
async delete(storeName, key) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], 'readwrite');
const store = transaction.objectStore(storeName);
const request = store.delete(key);
request.onsuccess = () => resolve();
request.onerror = () => reject(request.error);
});
}
}
四、electron-store #
4.1 安装与使用 #
bash
npm install electron-store
javascript
const Store = require('electron-store');
const store = new Store();
// 存储
store.set('username', 'John');
store.set('settings', {
theme: 'dark',
language: 'zh-CN'
});
// 读取
const username = store.get('username');
const theme = store.get('settings.theme');
// 默认值
const fontSize = store.get('fontSize', 14);
// 删除
store.delete('username');
// 清空
store.clear();
// 检查是否存在
store.has('username');
// 获取所有数据
store.store;
// 获取存储路径
store.path;
4.2 配置选项 #
javascript
const store = new Store({
// 配置文件名
name: 'config',
// 默认值
defaults: {
theme: 'light',
language: 'zh-CN',
window: {
width: 800,
height: 600
}
},
// 加密密钥(可选)
encryptionKey: 'my-secret-key',
// 自定义路径
cwd: app.getPath('userData'),
// 文件扩展名
fileExtension: 'json',
// 是否在退出时保存
accessPropertiesByDotNotation: true,
// 验证配置
schema: {
theme: {
type: 'string',
enum: ['light', 'dark']
},
language: {
type: 'string'
}
}
});
4.3 监听变化 #
javascript
// 监听所有变化
store.onDidAnyChange((newValue, oldValue) => {
console.log('配置已变化');
});
// 监听特定键
store.onDidChange('theme', (newValue, oldValue) => {
console.log(`主题从 ${oldValue} 变为 ${newValue}`);
});
4.4 多实例存储 #
javascript
// 用户配置
const userStore = new Store({ name: 'user' });
// 应用配置
const appStore = new Store({ name: 'app' });
// 缓存
const cacheStore = new Store({ name: 'cache' });
五、配置管理 #
5.1 配置管理器 #
javascript
// configManager.js
const Store = require('electron-store');
class ConfigManager {
constructor() {
this.store = new Store({
name: 'config',
defaults: {
general: {
theme: 'light',
language: 'zh-CN',
autoStart: false,
minimizeToTray: true
},
window: {
width: 1024,
height: 768,
x: undefined,
y: undefined,
isMaximized: false
},
shortcuts: {
showWindow: 'CommandOrControl+Shift+W',
quickCapture: 'CommandOrControl+Shift+C'
}
}
});
}
get(key, defaultValue) {
return this.store.get(key, defaultValue);
}
set(key, value) {
this.store.set(key, value);
}
getGeneral() {
return this.store.get('general');
}
setGeneral(config) {
this.store.set('general', { ...this.getGeneral(), ...config });
}
getWindowState() {
return this.store.get('window');
}
setWindowState(state) {
this.store.set('window', state);
}
reset() {
this.store.clear();
}
}
module.exports = new ConfigManager();
5.2 使用配置管理器 #
javascript
// main.js
const config = require('./configManager');
// 获取配置
const theme = config.get('general.theme');
// 设置配置
config.set('general.theme', 'dark');
// 保存窗口状态
config.setWindowState({
width: mainWindow.getSize()[0],
height: mainWindow.getSize()[1],
x: mainWindow.getPosition()[0],
y: mainWindow.getPosition()[1],
isMaximized: mainWindow.isMaximized()
});
六、缓存管理 #
6.1 缓存实现 #
javascript
// cacheManager.js
const Store = require('electron-store');
class CacheManager {
constructor() {
this.store = new Store({ name: 'cache' });
}
set(key, value, ttl = 0) {
const item = {
value,
timestamp: Date.now(),
ttl
};
this.store.set(key, item);
}
get(key) {
const item = this.store.get(key);
if (!item) return null;
// 检查是否过期
if (item.ttl > 0 && Date.now() - item.timestamp > item.ttl) {
this.delete(key);
return null;
}
return item.value;
}
delete(key) {
this.store.delete(key);
}
clear() {
this.store.clear();
}
clearExpired() {
const items = this.store.store;
const now = Date.now();
Object.keys(items).forEach(key => {
const item = items[key];
if (item.ttl > 0 && now - item.timestamp > item.ttl) {
this.delete(key);
}
});
}
}
module.exports = new CacheManager();
6.2 使用缓存 #
javascript
const cache = require('./cacheManager');
// 设置缓存,有效期 1 小时
cache.set('userData', userData, 3600000);
// 获取缓存
const userData = cache.get('userData');
// 清除过期缓存
cache.clearExpired();
七、数据迁移 #
7.1 版本迁移 #
javascript
class DataMigration {
constructor(store) {
this.store = store;
this.currentVersion = 2;
}
migrate() {
const version = this.store.get('version', 1);
if (version < 2) {
this.migrateToV2();
}
this.store.set('version', this.currentVersion);
}
migrateToV2() {
// 迁移旧数据格式
const oldTheme = this.store.get('theme');
if (oldTheme) {
this.store.set('general.theme', oldTheme);
this.store.delete('theme');
}
}
}
// 使用
const migration = new DataMigration(store);
migration.migrate();
八、数据备份 #
8.1 备份与恢复 #
javascript
const fs = require('fs');
const path = require('path');
class DataBackup {
constructor(store) {
this.store = store;
this.backupDir = path.join(app.getPath('userData'), 'backups');
if (!fs.existsSync(this.backupDir)) {
fs.mkdirSync(this.backupDir, { recursive: true });
}
}
backup(name) {
const backupPath = path.join(this.backupDir, `${name}.json`);
const data = JSON.stringify(this.store.store, null, 2);
fs.writeFileSync(backupPath, data);
return backupPath;
}
restore(name) {
const backupPath = path.join(this.backupDir, `${name}.json`);
if (fs.existsSync(backupPath)) {
const data = JSON.parse(fs.readFileSync(backupPath, 'utf-8'));
this.store.store = data;
return true;
}
return false;
}
listBackups() {
return fs.readdirSync(this.backupDir)
.filter(f => f.endsWith('.json'))
.map(f => f.replace('.json', ''));
}
deleteBackup(name) {
const backupPath = path.join(this.backupDir, `${name}.json`);
if (fs.existsSync(backupPath)) {
fs.unlinkSync(backupPath);
}
}
}
九、最佳实践 #
9.1 存储策略选择 #
javascript
// 根据数据类型选择存储方案
function chooseStorage(data) {
// 简单配置:electron-store
// 大量数据:IndexedDB
// 临时数据:sessionStorage
// 大文件:文件系统
}
9.2 数据加密 #
javascript
const crypto = require('crypto');
function encrypt(text, key) {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
let encrypted = cipher.update(text);
encrypted = Buffer.concat([encrypted, cipher.final()]);
return iv.toString('hex') + ':' + encrypted.toString('hex');
}
function decrypt(text, key) {
const [ivHex, encryptedHex] = text.split(':');
const iv = Buffer.from(ivHex, 'hex');
const encrypted = Buffer.from(encryptedHex, 'hex');
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
let decrypted = decipher.update(encrypted);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString();
}
十、总结 #
10.1 核心要点 #
| 要点 | 说明 |
|---|---|
| localStorage | 简单键值对存储 |
| IndexedDB | 结构化大数据存储 |
| electron-store | 推荐的应用配置存储 |
| 配置管理 | 统一管理应用配置 |
| 数据迁移 | 版本升级时迁移数据 |
10.2 下一步 #
现在你已经掌握了本地存储,接下来让我们学习 文件系统操作,深入了解 Node.js 文件操作 API!
最后更新:2026-03-28