Harmony学习之本地数据存储
一、场景引入
小明在上一篇文章中学会了网络请求,现在他需要将用户登录信息、应用配置、商品收藏等数据持久化保存到本地,这样即使应用重启或网络断开,用户也能看到自己的个性化设置和历史数据。本篇文章将系统讲解HarmonyOS的本地数据存储机制,帮助小明实现数据的本地持久化。
二、本地数据存储方案对比
HarmonyOS提供了多种本地数据存储方式,每种方式都有其适用场景:
| 存储方式 | 适用场景 | 特点 |
|---|---|---|
| Preferences | 用户配置、登录状态、开关设置 | 轻量级键值对存储,类似SharedPreferences |
| 关系型数据库 | 结构化数据、复杂查询、事务支持 | 基于SQLite,支持ACID事务 |
| 文件存储 | 大文件、图片、文档 | 支持二进制流和文本操作 |
三、Preferences轻量级存储
1. 核心概念
Preferences是HarmonyOS提供的轻量级键值对存储方案,适合存储用户配置、应用设置等小数据量信息。数据以Key-Value形式存储,支持字符串、数字、布尔值等基本数据类型。
2. 基本使用
// src/main/ets/common/StorageUtil.ts import preferences from '@ohos.data.preferences'; export class StorageUtil { private static instance: StorageUtil; private preferences: preferences.Preferences | null = null; // 获取Preferences实例 public static async getInstance(): Promise<StorageUtil> { if (!StorageUtil.instance) { StorageUtil.instance = new StorageUtil(); await StorageUtil.instance.init(); } return StorageUtil.instance; } // 初始化Preferences private async init() { try { this.preferences = await preferences.getPreferences( globalThis.getContext(), 'app_config' ); } catch (error) { console.error('初始化Preferences失败:', error); } } // 保存数据 public async save(key: string, value: any): Promise<boolean> { if (!this.preferences) return false; try { await this.preferences.put(key, value); await this.preferences.flush(); // 持久化到文件 return true; } catch (error) { console.error('保存数据失败:', error); return false; } } // 读取数据 public async get<T>(key: string, defaultValue: T): Promise<T> { if (!this.preferences) return defaultValue; try { return await this.preferences.get(key, defaultValue); } catch (error) { console.error('读取数据失败:', error); return defaultValue; } } // 删除数据 public async delete(key: string): Promise<boolean> { if (!this.preferences) return false; try { await this.preferences.delete(key); await this.preferences.flush(); return true; } catch (error) { console.error('删除数据失败:', error); return false; } } }3. 实战应用:保存用户登录状态
// src/main/ets/pages/Login.ets import { StorageUtil } from '../common/StorageUtil'; @Entry @Component struct Login { @State username: string = ''; @State password: string = ''; build() { Column({ space: 20 }) { // ... 登录表单UI代码 Button('登录') .onClick(() => { this.handleLogin(); }) } } // 处理登录 private async handleLogin() { // 验证用户名密码... // 保存登录状态 const storage = await StorageUtil.getInstance(); await storage.save('isLoggedIn', true); await storage.save('username', this.username); // 跳转到首页 router.replaceUrl({ url: 'pages/Home' }); } }四、关系型数据库存储
1. 核心概念
关系型数据库基于SQLite组件,提供结构化数据存储能力,支持复杂的查询、事务、索引等功能。适合存储用户信息、商品数据、订单记录等结构化数据。
2. 数据库创建与表定义
// src/main/ets/database/DatabaseHelper.ts import relationalStore from '@ohos.data.relationalStore'; // 用户表定义 export interface User { id?: number; name: string; email: string; age: number; createTime: number; } export class DatabaseHelper { private static instance: DatabaseHelper; private rdbStore: relationalStore.RdbStore | null = null; // 数据库配置 private readonly DB_NAME = 'app_database.db'; private readonly DB_VERSION = 1; // 创建用户表SQL private readonly CREATE_USER_TABLE = ` CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT UNIQUE NOT NULL, age INTEGER, createTime INTEGER DEFAULT (strftime('%s', 'now')) ) `; // 获取单例实例 public static async getInstance(): Promise<DatabaseHelper> { if (!DatabaseHelper.instance) { DatabaseHelper.instance = new DatabaseHelper(); await DatabaseHelper.instance.init(); } return DatabaseHelper.instance; } // 初始化数据库 private async init() { try { const context = globalThis.getContext(); const storeConfig: relationalStore.StoreConfig = { name: this.DB_NAME, securityLevel: relationalStore.SecurityLevel.S1 }; this.rdbStore = await relationalStore.getRdbStore(context, storeConfig); // 创建表 await this.rdbStore.executeSql(this.CREATE_USER_TABLE); console.log('数据库初始化成功'); } catch (error) { console.error('数据库初始化失败:', error); } } }3. 增删改查操作
// 在DatabaseHelper类中继续添加方法 // 插入用户 public async insertUser(user: User): Promise<number> { if (!this.rdbStore) return -1; try { const valueBucket: relationalStore.ValuesBucket = { 'name': user.name, 'email': user.email, 'age': user.age }; const rowId = await this.rdbStore.insert('users', valueBucket); return rowId; } catch (error) { console.error('插入用户失败:', error); return -1; } } // 查询用户 public async queryUsers(): Promise<User[]> { if (!this.rdbStore) return []; try { const predicates = new relationalStore.RdbPredicates('users'); const columns = ['id', 'name', 'email', 'age', 'createTime']; const resultSet = await this.rdbStore.query(predicates, columns); const users: User[] = []; while (resultSet.goToNextRow()) { users.push({ id: resultSet.getLong(resultSet.getColumnIndex('id')), name: resultSet.getString(resultSet.getColumnIndex('name')), email: resultSet.getString(resultSet.getColumnIndex('email')), age: resultSet.getLong(resultSet.getColumnIndex('age')), createTime: resultSet.getLong(resultSet.getColumnIndex('createTime')) }); } resultSet.close(); return users; } catch (error) { console.error('查询用户失败:', error); return []; } } // 更新用户 public async updateUser(user: User): Promise<boolean> { if (!this.rdbStore || !user.id) return false; try { const predicates = new relationalStore.RdbPredicates('users'); predicates.equalTo('id', user.id); const valueBucket: relationalStore.ValuesBucket = { 'name': user.name, 'email': user.email, 'age': user.age }; const affectedRows = await this.rdbStore.update(valueBucket, predicates); return affectedRows > 0; } catch (error) { console.error('更新用户失败:', error); return false; } } // 删除用户 public async deleteUser(id: number): Promise<boolean> { if (!this.rdbStore) return false; try { const predicates = new relationalStore.RdbPredicates('users'); predicates.equalTo('id', id); const affectedRows = await this.rdbStore.delete(predicates); return affectedRows > 0; } catch (error) { console.error('删除用户失败:', error); return false; } }4. 实战应用:用户管理
// src/main/ets/pages/UserList.ets import { DatabaseHelper, User } from '../database/DatabaseHelper'; @Entry @Component struct UserList { @State users: User[] = []; aboutToAppear() { this.loadUsers(); } build() { Column() { List() { ForEach(this.users, (user: User) => { ListItem() { Column() { Text(user.name) .fontSize(18) Text(user.email) .fontSize(14) .fontColor(Color.Gray) } .padding(10) } }) } .layoutWeight(1) } } // 加载用户列表 private async loadUsers() { const dbHelper = await DatabaseHelper.getInstance(); this.users = await dbHelper.queryUsers(); } }五、文件存储
1. 核心概念
文件存储适用于保存图片、文档、大体积数据等二进制内容。HarmonyOS提供了文件系统API,支持文件的创建、读写、删除等操作。
2. 文件操作示例
// src/main/ets/common/FileUtil.ts import fs from '@ohos.file.fs'; export class FileUtil { // 写入文件 public static async writeFile(filePath: string, content: string): Promise<boolean> { try { const file = await fs.open(filePath, fs.OpenMode.CREATE | fs.OpenMode.WRITE); await fs.write(file.fd, content); await fs.close(file.fd); return true; } catch (error) { console.error('写入文件失败:', error); return false; } } // 读取文件 public static async readFile(filePath: string): Promise<string> { try { const file = await fs.open(filePath, fs.OpenMode.READ_ONLY); const stat = await fs.stat(filePath); const buffer = new ArrayBuffer(stat.size); await fs.read(file.fd, buffer); await fs.close(file.fd); const textDecoder = new util.TextDecoder(); return textDecoder.decode(buffer); } catch (error) { console.error('读取文件失败:', error); return ''; } } // 获取应用私有目录 public static getFilesDir(): string { const context = globalThis.getContext(); return context.filesDir; } }六、最佳实践
1. 数据存储选型指南
Preferences适用场景:
- 用户配置信息(主题、语言、字体大小)
- 登录状态、Token等敏感信息
- 简单的开关设置
关系型数据库适用场景:
- 用户信息、商品列表等结构化数据
- 需要复杂查询、排序、分页的场景
- 需要事务支持的业务数据
文件存储适用场景:
- 图片、视频、文档等大文件
- 日志文件、缓存数据
- 需要导出/导入的数据
2. 性能优化建议
Preferences优化:
- 批量操作时先put再flush,减少IO次数
- 避免存储大JSON对象,建议使用数据库
- 及时清理不再使用的数据
数据库优化:
- 为常用查询字段创建索引
- 使用事务处理批量操作
- 避免在主线程执行耗时查询
文件存储优化:
- 大文件使用流式读写
- 定期清理缓存文件
- 使用临时目录存储临时文件
3. 错误处理与调试
// 完整的错误处理示例 try { const dbHelper = await DatabaseHelper.getInstance(); const users = await dbHelper.queryUsers(); // 处理数据... } catch (error) { console.error('数据库操作失败:', error); promptAction.showToast({ message: '数据加载失败,请稍后重试', duration: 2000 }); }七、总结与行动建议
核心要点回顾
- Preferences:轻量级键值对存储,适合配置信息
- 关系型数据库:结构化数据存储,支持复杂查询
- 文件存储:大文件、二进制数据存储
- 选型原则:根据数据特点和业务需求选择合适的存储方案
行动建议
- 动手实践:创建用户配置页面,使用Preferences保存主题设置
- 数据库实战:实现一个简单的待办事项应用,使用数据库存储任务数据
- 文件操作:实现图片缓存功能,将网络图片保存到本地
- 性能优化:为数据库查询添加索引,优化查询性能
通过本篇文章的学习,你已经掌握了HarmonyOS本地数据存储的核心能力。下一篇文章将深入讲解列表渲染与性能优化,帮助你实现高效的数据展示和交互体验。