存储系统 #

一、存储方案概述 #

1.1 存储类型对比 #

存储方案 容量 持久化 适用场景
Preferences 小量 配置、设置
文件系统 大量 文件、缓存
SQLite 大量 结构化数据
IndexedDB 大量 Web端大数据
内存存储 中量 临时数据

二、Preferences插件 #

2.1 安装 #

bash
npm install @capacitor/preferences
npx cap sync

2.2 基本使用 #

typescript
import { Preferences } from '@capacitor/preferences';

// 存储数据
await Preferences.set({
    key: 'username',
    value: 'john_doe'
});

// 读取数据
const { value } = await Preferences.get({ key: 'username' });
console.log(value); // 'john_doe'

// 删除数据
await Preferences.remove({ key: 'username' });

// 清空所有数据
await Preferences.clear();

// 获取所有键
const { keys } = await Preferences.keys();
console.log(keys); // ['key1', 'key2', ...]

2.3 存储对象 #

typescript
// 存储对象
async function setObject<T>(key: string, value: T): Promise<void> {
    await Preferences.set({
        key,
        value: JSON.stringify(value)
    });
}

// 读取对象
async function getObject<T>(key: string): Promise<T | null> {
    const { value } = await Preferences.get({ key });
    return value ? JSON.parse(value) : null;
}

// 使用示例
interface User {
    id: string;
    name: string;
    email: string;
}

await setObject<User>('user', {
    id: '1',
    name: 'John',
    email: 'john@example.com'
});

const user = await getObject<User>('user');

2.4 封装存储服务 #

typescript
// src/services/storage.service.ts
import { Preferences } from '@capacitor/preferences';

class StorageService {
    private prefix = 'app_';
    
    async set<T>(key: string, value: T): Promise<void> {
        await Preferences.set({
            key: `${this.prefix}${key}`,
            value: JSON.stringify(value)
        });
    }
    
    async get<T>(key: string, defaultValue?: T): Promise<T | undefined> {
        const { value } = await Preferences.get({
            key: `${this.prefix}${key}`
        });
        
        if (value === null) {
            return defaultValue;
        }
        
        try {
            return JSON.parse(value) as T;
        } catch {
            return value as unknown as T;
        }
    }
    
    async remove(key: string): Promise<void> {
        await Preferences.remove({
            key: `${this.prefix}${key}`
        });
    }
    
    async clear(): Promise<void> {
        const { keys } = await Preferences.keys();
        for (const key of keys) {
            if (key.startsWith(this.prefix)) {
                await Preferences.remove({ key });
            }
        }
    }
    
    async has(key: string): Promise<boolean> {
        const { value } = await Preferences.get({
            key: `${this.prefix}${key}`
        });
        return value !== null;
    }
}

export const storageService = new StorageService();

三、文件系统插件 #

3.1 安装 #

bash
npm install @capacitor/filesystem
npx cap sync

3.2 权限配置 #

Android (AndroidManifest.xml):

xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

3.3 基本操作 #

typescript
import { Filesystem, Directory, Encoding } from '@capacitor/filesystem';

// 写入文件
async function writeFile() {
    await Filesystem.writeFile({
        path: 'mydir/myfile.txt',
        data: 'Hello, Capacitor!',
        directory: Directory.Documents,
        encoding: Encoding.UTF8
    });
}

// 读取文件
async function readFile() {
    const result = await Filesystem.readFile({
        path: 'mydir/myfile.txt',
        directory: Directory.Documents,
        encoding: Encoding.UTF8
    });
    
    console.log(result.data); // 'Hello, Capacitor!'
}

// 删除文件
async function deleteFile() {
    await Filesystem.deleteFile({
        path: 'mydir/myfile.txt',
        directory: Directory.Documents
    });
}

// 检查文件是否存在
async function fileExists() {
    try {
        await Filesystem.stat({
            path: 'mydir/myfile.txt',
            directory: Directory.Documents
        });
        return true;
    } catch {
        return false;
    }
}

3.4 目录操作 #

typescript
import { Filesystem, Directory } from '@capacitor/filesystem';

// 创建目录
async function createDirectory() {
    await Filesystem.mkdir({
        path: 'mydir/subdir',
        directory: Directory.Documents,
        recursive: true  // 递归创建
    });
}

// 删除目录
async function removeDirectory() {
    await Filesystem.rmdir({
        path: 'mydir',
        directory: Directory.Documents,
        recursive: true  // 递归删除
    });
}

// 列出目录内容
async function listDirectory() {
    const result = await Filesystem.readdir({
        path: 'mydir',
        directory: Directory.Documents
    });
    
    console.log(result.files);
    // [{ name: 'file1.txt', type: 'file' }, { name: 'subdir', type: 'directory' }]
}

3.5 存储目录 #

typescript
enum Directory {
    Documents,    // 文档目录
    Data,         // 应用数据目录
    Cache,        // 缓存目录
    External,     // 外部存储(Android)
    ExternalStorage // 外部存储根目录(Android)
}

3.6 文件URI操作 #

typescript
// 获取文件URI
async function getFileUri() {
    const result = await Filesystem.getUri({
        path: 'mydir/myfile.txt',
        directory: Directory.Documents
    });
    
    console.log(result.uri);
    // iOS: file:///var/mobile/Containers/Data/.../mydir/myfile.txt
    // Android: file:///data/user/0/com.example.app/files/mydir/myfile.txt
}

// 复制文件
async function copyFile() {
    await Filesystem.copy({
        from: 'source.txt',
        to: 'destination.txt',
        directory: Directory.Documents
    });
}

// 移动文件
async function moveFile() {
    await Filesystem.move({
        from: 'oldpath.txt',
        to: 'newpath.txt',
        directory: Directory.Documents
    });
}

3.7 二进制文件 #

typescript
// 写入Base64数据
async function writeBinaryFile(base64Data: string) {
    await Filesystem.writeFile({
        path: 'image.jpg',
        data: base64Data,
        directory: Directory.Documents
    });
}

// 读取为Base64
async function readBinaryFile() {
    const result = await Filesystem.readFile({
        path: 'image.jpg',
        directory: Directory.Documents
    });
    
    // result.data 是Base64字符串
    return result.data;
}

四、SQLite数据库 #

4.1 安装社区插件 #

bash
npm install @capacitor-community/sqlite
npx cap sync

4.2 基本使用 #

typescript
import { CapacitorSQLite, SQLiteConnection, SQLiteDBConnection } from '@capacitor-community/sqlite';

const sqlite = new SQLiteConnection(CapacitorSQLite);

// 创建/打开数据库
async function openDatabase(): Promise<SQLiteDBConnection> {
    const db = await sqlite.createConnection(
        'mydb',
        false,  // encrypted
        'no-encryption',
        1       // version
    );
    
    await db.open();
    
    return db;
}

// 创建表
async function createTable(db: SQLiteDBConnection) {
    await db.execute(`
        CREATE TABLE IF NOT EXISTS users (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            email TEXT UNIQUE,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP
        )
    `);
}

// 插入数据
async function insertUser(db: SQLiteDBConnection, name: string, email: string) {
    await db.run(
        'INSERT INTO users (name, email) VALUES (?, ?)',
        [name, email]
    );
}

// 查询数据
async function getUsers(db: SQLiteDBConnection) {
    const result = await db.query('SELECT * FROM users');
    return result.values;
}

// 更新数据
async function updateUser(db: SQLiteDBConnection, id: number, name: string) {
    await db.run(
        'UPDATE users SET name = ? WHERE id = ?',
        [name, id]
    );
}

// 删除数据
async function deleteUser(db: SQLiteDBConnection, id: number) {
    await db.run('DELETE FROM users WHERE id = ?', [id]);
}

4.3 封装SQLite服务 #

typescript
// src/services/database.service.ts
import { CapacitorSQLite, SQLiteConnection, SQLiteDBConnection } from '@capacitor-community/sqlite';

class DatabaseService {
    private sqlite: SQLiteConnection;
    private db: SQLiteDBConnection | null = null;
    private dbName = 'app_database';
    
    constructor() {
        this.sqlite = new SQLiteConnection(CapacitorSQLite);
    }
    
    async init(): Promise<void> {
        this.db = await this.sqlite.createConnection(
            this.dbName,
            false,
            'no-encryption',
            1
        );
        
        await this.db.open();
        await this.createTables();
    }
    
    private async createTables(): Promise<void> {
        if (!this.db) return;
        
        await this.db.execute(`
            CREATE TABLE IF NOT EXISTS users (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                name TEXT NOT NULL,
                email TEXT UNIQUE
            );
            
            CREATE TABLE IF NOT EXISTS tasks (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                title TEXT NOT NULL,
                completed INTEGER DEFAULT 0,
                user_id INTEGER,
                FOREIGN KEY (user_id) REFERENCES users(id)
            );
        `);
    }
    
    async query<T>(sql: string, params: any[] = []): Promise<T[]> {
        if (!this.db) throw new Error('Database not initialized');
        
        const result = await this.db.query(sql, params);
        return result.values || [];
    }
    
    async run(sql: string, params: any[] = []): Promise<{ changes: number; lastId: number }> {
        if (!this.db) throw new Error('Database not initialized');
        
        const result = await this.db.run(sql, params);
        return {
            changes: result.changes?.changes || 0,
            lastId: result.changes?.lastId || 0
        };
    }
    
    async transaction<T>(callback: () => Promise<T>): Promise<T> {
        if (!this.db) throw new Error('Database not initialized');
        
        await this.db.execute('BEGIN TRANSACTION');
        
        try {
            const result = await callback();
            await this.db.execute('COMMIT');
            return result;
        } catch (error) {
            await this.db.execute('ROLLBACK');
            throw error;
        }
    }
    
    async close(): Promise<void> {
        if (this.db) {
            await this.sqlite.closeConnection(this.dbName, false);
            this.db = null;
        }
    }
}

export const databaseService = new DatabaseService();

五、缓存管理 #

5.1 缓存服务 #

typescript
// src/services/cache.service.ts
import { Preferences } from '@capacitor/preferences';

interface CacheItem<T> {
    data: T;
    timestamp: number;
    ttl: number;
}

class CacheService {
    private prefix = 'cache_';
    
    async set<T>(key: string, data: T, ttl: number = 3600000): Promise<void> {
        const item: CacheItem<T> = {
            data,
            timestamp: Date.now(),
            ttl
        };
        
        await Preferences.set({
            key: `${this.prefix}${key}`,
            value: JSON.stringify(item)
        });
    }
    
    async get<T>(key: string): Promise<T | null> {
        const { value } = await Preferences.get({
            key: `${this.prefix}${key}`
        });
        
        if (!value) return null;
        
        const item: CacheItem<T> = JSON.parse(value);
        
        // 检查是否过期
        if (Date.now() - item.timestamp > item.ttl) {
            await this.remove(key);
            return null;
        }
        
        return item.data;
    }
    
    async remove(key: string): Promise<void> {
        await Preferences.remove({
            key: `${this.prefix}${key}`
        });
    }
    
    async clear(): Promise<void> {
        const { keys } = await Preferences.keys();
        
        for (const key of keys) {
            if (key.startsWith(this.prefix)) {
                await Preferences.remove({ key });
            }
        }
    }
    
    async has(key: string): Promise<boolean> {
        const data = await this.get(key);
        return data !== null;
    }
}

export const cacheService = new CacheService();

5.2 使用缓存 #

typescript
// 带缓存的数据获取
async function fetchWithCache<T>(
    key: string,
    fetcher: () => Promise<T>,
    ttl: number = 3600000
): Promise<T> {
    // 尝试从缓存获取
    const cached = await cacheService.get<T>(key);
    
    if (cached !== null) {
        return cached;
    }
    
    // 获取新数据
    const data = await fetcher();
    
    // 存入缓存
    await cacheService.set(key, data, ttl);
    
    return data;
}

// 使用示例
interface User {
    id: string;
    name: string;
}

async function getUser(id: string): Promise<User> {
    return fetchWithCache(
        `user_${id}`,
        () => fetch(`/api/users/${id}`).then(r => r.json()),
        60000  // 1分钟缓存
    );
}

六、数据迁移 #

6.1 版本迁移 #

typescript
class DataMigration {
    private currentVersion = 1;
    
    async migrate(): Promise<void> {
        const { value } = await Preferences.get({ key: 'db_version' });
        const version = value ? parseInt(value) : 0;
        
        if (version < 1) {
            await this.migrateToV1();
        }
        
        // 未来版本迁移
        // if (version < 2) {
        //     await this.migrateToV2();
        // }
        
        await Preferences.set({
            key: 'db_version',
            value: this.currentVersion.toString()
        });
    }
    
    private async migrateToV1(): Promise<void> {
        // V1迁移逻辑
        console.log('Migrating to V1...');
    }
}

七、完整示例 #

7.1 用户数据管理 #

typescript
// src/services/user-data.service.ts
import { storageService } from './storage.service';
import { cacheService } from './cache.service';

interface UserData {
    profile: {
        name: string;
        email: string;
        avatar?: string;
    };
    settings: {
        theme: 'light' | 'dark';
        language: string;
        notifications: boolean;
    };
    lastSync: number;
}

class UserDataService {
    private readonly PROFILE_KEY = 'user_profile';
    private readonly SETTINGS_KEY = 'user_settings';
    
    async getProfile() {
        return storageService.get<UserData['profile']>(this.PROFILE_KEY);
    }
    
    async setProfile(profile: UserData['profile']): Promise<void> {
        await storageService.set(this.PROFILE_KEY, profile);
        await cacheService.remove('user_full_data');
    }
    
    async getSettings() {
        const defaultSettings: UserData['settings'] = {
            theme: 'light',
            language: 'zh-CN',
            notifications: true
        };
        
        return storageService.get<UserData['settings']>(
            this.SETTINGS_KEY,
            defaultSettings
        );
    }
    
    async updateSettings(settings: Partial<UserData['settings']>): Promise<void> {
        const current = await this.getSettings();
        await storageService.set(this.SETTINGS_KEY, {
            ...current,
            ...settings
        });
    }
    
    async getFullData(): Promise<UserData> {
        return cacheService.get<UserData>('user_full_data') || {
            profile: await this.getProfile(),
            settings: await this.getSettings(),
            lastSync: Date.now()
        };
    }
    
    async clearAll(): Promise<void> {
        await storageService.remove(this.PROFILE_KEY);
        await storageService.remove(this.SETTINGS_KEY);
        await cacheService.clear();
    }
}

export const userDataService = new UserDataService();

八、总结 #

8.1 存储方案选择 #

数据类型 推荐方案
配置设置 Preferences
简单数据 Preferences
文件/图片 Filesystem
结构化数据 SQLite
临时缓存 内存/Preferences

8.2 下一步 #

了解存储系统后,让我们学习 推送通知

最后更新:2026-03-28