鸿蒙开发之:本地数据存储方案
在移动应用开发中,本地数据存储是必不可少的功能。实现离线使用:在没有网络的情况下正常使用提升性能:减少网络请求,快速加载数据保存用户偏好:记住用户的设置和偏好缓存数据:临时存储网络数据,减少流量消耗鸿蒙提供了多种本地存储方案,每种方案都有其适用的场景。:轻量级键值存储,适合简单配置关系型数据库:复杂数据存储,支持SQL查询文件存储:大文件和自定义格式数据存储数据加密:敏感数据的安全存储存储策略:如
本文字数:约3200字 | 预计阅读时间:13分钟
前置知识:建议先学习本系列前五篇,特别是网络请求与数据处理
实战价值:掌握本地存储,让应用具备离线能力,提升用户体验
系列导航:本文是《鸿蒙开发系列》第6篇,下篇将讲解服务卡片开发实战
一、本地存储概述
在移动应用开发中,本地数据存储是必不可少的功能。它可以让应用:
-
实现离线使用:在没有网络的情况下正常使用
-
提升性能:减少网络请求,快速加载数据
-
保存用户偏好:记住用户的设置和偏好
-
缓存数据:临时存储网络数据,减少流量消耗
鸿蒙提供了多种本地存储方案,每种方案都有其适用的场景。
二、Preferences:轻量级键值存储
Preferences是鸿蒙提供的轻量级存储方案,适合存储简单的键值对数据,如用户设置、登录状态等。
2.1 基本使用
typescript
import dataPreferences from '@ohos.data.preferences';
class PreferencesManager {
private preferences: dataPreferences.Preferences | null = null;
// 初始化Preferences
async init(context: any, name: string = 'myPreferences') {
try {
this.preferences = await dataPreferences.getPreferences(context, name);
console.log('Preferences初始化成功');
} catch (error) {
console.error('Preferences初始化失败:', error);
}
}
// 保存数据
async set(key: string, value: dataPreferences.ValueType) {
if (!this.preferences) {
throw new Error('Preferences未初始化');
}
try {
await this.preferences.put(key, value);
await this.preferences.flush(); // 持久化到磁盘
return true;
} catch (error) {
console.error('保存数据失败:', error);
return false;
}
}
// 获取数据
async get(key: string, defaultValue: dataPreferences.ValueType = '') {
if (!this.preferences) {
throw new Error('Preferences未初始化');
}
try {
const value = await this.preferences.get(key, defaultValue);
return value;
} catch (error) {
console.error('获取数据失败:', error);
return defaultValue;
}
}
// 删除数据
async delete(key: string) {
if (!this.preferences) {
throw new Error('Preferences未初始化');
}
try {
await this.preferences.delete(key);
await this.preferences.flush();
return true;
} catch (error) {
console.error('删除数据失败:', error);
return false;
}
}
// 清空所有数据
async clear() {
if (!this.preferences) {
throw new Error('Preferences未初始化');
}
try {
await this.preferences.clear();
await this.preferences.flush();
return true;
} catch (error) {
console.error('清空数据失败:', error);
return false;
}
}
}
// 全局实例
export const preferencesManager = new PreferencesManager();
2.2 在应用中使用
typescript
@Entry
@Component
struct SettingsPage {
@State username: string = '';
@State rememberMe: boolean = false;
@State fontSize: number = 16;
async aboutToAppear() {
// 初始化Preferences
await preferencesManager.init(getContext(this));
// 加载保存的设置
this.username = (await preferencesManager.get('username', '')) as string;
this.rememberMe = (await preferencesManager.get('rememberMe', false)) as boolean;
this.fontSize = (await preferencesManager.get('fontSize', 16)) as number;
}
async saveSettings() {
await preferencesManager.set('username', this.username);
await preferencesManager.set('rememberMe', this.rememberMe);
await preferencesManager.set('fontSize', this.fontSize);
// 显示保存成功提示
prompt.showToast({ message: '设置已保存' });
}
build() {
Column({ space: 20 }) {
Text('应用设置')
.fontSize(24)
.fontWeight(FontWeight.Bold)
// 用户名设置
Column({ space: 8 }) {
Text('用户名')
.fontSize(16)
.fontColor('#333333')
TextInput({ placeholder: '请输入用户名' })
.width('100%')
.height(48)
.fontSize(this.fontSize)
.value(this.username)
.onChange((value: string) => {
this.username = value;
})
}
// 记住我选项
Row({ space: 10 }) {
Checkbox()
.select(this.rememberMe)
.onChange((checked: boolean) => {
this.rememberMe = checked;
})
Text('记住登录状态')
.fontSize(16)
}
// 字体大小设置
Column({ space: 8 }) {
Text(`字体大小:${this.fontSize}`)
.fontSize(16)
Slider({
value: this.fontSize,
min: 12,
max: 24,
step: 1,
style: SliderStyle.InSet
})
.width('100%')
.onChange((value: number) => {
this.fontSize = value;
})
}
// 保存按钮
Button('保存设置')
.width('100%')
.height(50)
.fontSize(18)
.onClick(() => {
this.saveSettings();
})
}
.width('100%')
.height('100%')
.padding(20)
}
}
三、关系型数据库:SQLite
对于需要复杂查询和事务支持的数据存储,鸿蒙提供了关系型数据库(基于SQLite)的支持。
3.1 数据库管理类
typescript
import relationalStore from '@ohos.data.relationalStore';
// 定义用户表结构
const USER_TABLE = 'users';
const USER_SCHEMA = {
tableName: USER_TABLE,
columns: [
{ fieldName: 'id', columnName: 'id', type: relationalStore.ValueType.INTEGER, isPrimaryKey: true },
{ fieldName: 'name', columnName: 'name', type: relationalStore.ValueType.STRING },
{ fieldName: 'email', columnName: 'email', type: relationalStore.ValueType.STRING },
{ fieldName: 'age', columnName: 'age', type: relationalStore.ValueType.INTEGER },
{ fieldName: 'createdAt', columnName: 'created_at', type: relationalStore.ValueType.INTEGER },
{ fieldName: 'updatedAt', columnName: 'updated_at', type: relationalStore.ValueType.INTEGER }
]
};
class DatabaseManager {
private rdbStore: relationalStore.RdbStore | null = null;
// 初始化数据库
async init(context: any) {
const config: relationalStore.StoreConfig = {
name: 'myApp.db',
securityLevel: relationalStore.SecurityLevel.S1
};
try {
this.rdbStore = await relationalStore.getRdbStore(context, config);
// 创建用户表
await this.createTable(USER_SCHEMA);
console.log('数据库初始化成功');
} catch (error) {
console.error('数据库初始化失败:', error);
}
}
// 创建表
private async createTable(schema: any) {
if (!this.rdbStore) return;
const sql = `
CREATE TABLE IF NOT EXISTS ${schema.tableName} (
${schema.columns.map((col: any) =>
`${col.columnName} ${this.getSqlType(col.type)} ${col.isPrimaryKey ? 'PRIMARY KEY' : ''}`
).join(', ')}
)
`;
await this.rdbStore.executeSql(sql);
}
// 类型映射
private getSqlType(type: relationalStore.ValueType): string {
switch (type) {
case relationalStore.ValueType.INTEGER: return 'INTEGER';
case relationalStore.ValueType.STRING: return 'TEXT';
case relationalStore.ValueType.FLOAT: return 'REAL';
case relationalStore.ValueType.BLOB: return 'BLOB';
default: return 'TEXT';
}
}
// 插入用户
async insertUser(user: { name: string, email: string, age: number }) {
if (!this.rdbStore) return false;
const valueBucket: relationalStore.ValuesBucket = {
'name': user.name,
'email': user.email,
'age': user.age,
'created_at': Date.now(),
'updated_at': Date.now()
};
try {
const rowId = await this.rdbStore.insert(USER_TABLE, valueBucket);
return rowId > 0;
} catch (error) {
console.error('插入用户失败:', error);
return false;
}
}
// 查询所有用户
async getAllUsers(): Promise<any[]> {
if (!this.rdbStore) return [];
const predicates = new relationalStore.RdbPredicates(USER_TABLE);
predicates.orderByAsc('created_at');
try {
const resultSet = await this.rdbStore.query(predicates, [
'id', 'name', 'email', 'age', 'created_at', 'updated_at'
]);
const users: any[] = [];
while (resultSet.goToNextRow()) {
users.push({
id: resultSet.getDouble(resultSet.getColumnIndex('id')),
name: resultSet.getString(resultSet.getColumnIndex('name')),
email: resultSet.getString(resultSet.getColumnIndex('email')),
age: resultSet.getDouble(resultSet.getColumnIndex('age')),
createdAt: resultSet.getDouble(resultSet.getColumnIndex('created_at')),
updatedAt: resultSet.getDouble(resultSet.getColumnIndex('updated_at'))
});
}
resultSet.close();
return users;
} catch (error) {
console.error('查询用户失败:', error);
return [];
}
}
// 更新用户
async updateUser(id: number, updates: Partial<{ name: string, email: string, age: number }>) {
if (!this.rdbStore) return false;
const predicates = new relationalStore.RdbPredicates(USER_TABLE);
predicates.equalTo('id', id);
const valueBucket: relationalStore.ValuesBucket = {
'updated_at': Date.now()
};
if (updates.name) valueBucket['name'] = updates.name;
if (updates.email) valueBucket['email'] = updates.email;
if (updates.age) valueBucket['age'] = updates.age;
try {
const rowsUpdated = await this.rdbStore.update(valueBucket, predicates);
return rowsUpdated > 0;
} catch (error) {
console.error('更新用户失败:', error);
return false;
}
}
// 删除用户
async deleteUser(id: number) {
if (!this.rdbStore) return false;
const predicates = new relationalStore.RdbPredicates(USER_TABLE);
predicates.equalTo('id', id);
try {
const rowsDeleted = await this.rdbStore.delete(predicates);
return rowsDeleted > 0;
} catch (error) {
console.error('删除用户失败:', error);
return false;
}
}
// 事务操作
async batchInsertUsers(users: Array<{ name: string, email: string, age: number }>) {
if (!this.rdbStore) return false;
try {
await this.rdbStore.beginTransaction();
for (const user of users) {
await this.insertUser(user);
}
await this.rdbStore.commit();
return true;
} catch (error) {
await this.rdbStore.rollback();
console.error('批量插入失败:', error);
return false;
}
}
}
export const databaseManager = new DatabaseManager();
3.2 用户管理界面
typescript
@Entry
@Component
struct UserManagerPage {
@State users: any[] = [];
@State loading: boolean = false;
@State newUserName: string = '';
@State newUserEmail: string = '';
@State newUserAge: string = '';
async aboutToAppear() {
await databaseManager.init(getContext(this));
this.loadUsers();
}
async loadUsers() {
this.loading = true;
this.users = await databaseManager.getAllUsers();
this.loading = false;
}
async addUser() {
if (!this.newUserName.trim() || !this.newUserEmail.trim()) {
prompt.showToast({ message: '请填写完整信息' });
return;
}
const age = parseInt(this.newUserAge) || 0;
const success = await databaseManager.insertUser({
name: this.newUserName,
email: this.newUserEmail,
age: age
});
if (success) {
prompt.showToast({ message: '用户添加成功' });
this.newUserName = '';
this.newUserEmail = '';
this.newUserAge = '';
this.loadUsers();
}
}
async deleteUser(id: number) {
const success = await databaseManager.deleteUser(id);
if (success) {
prompt.showToast({ message: '用户删除成功' });
this.loadUsers();
}
}
build() {
Column({ space: 20 }) {
Text('用户管理')
.fontSize(24)
.fontWeight(FontWeight.Bold)
// 添加用户表单
Column({ space: 12 }) {
TextInput({ placeholder: '姓名' })
.width('100%')
.height(48)
.value(this.newUserName)
.onChange((value: string) => {
this.newUserName = value;
})
TextInput({ placeholder: '邮箱' })
.width('100%')
.height(48)
.value(this.newUserEmail)
.onChange((value: string) => {
this.newUserEmail = value;
})
TextInput({ placeholder: '年龄' })
.width('100%')
.height(48)
.value(this.newUserAge)
.onChange((value: string) => {
this.newUserAge = value;
})
Button('添加用户')
.width('100%')
.height(50)
.onClick(() => {
this.addUser();
})
}
.padding(20)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({ radius: 4, color: '#10000000' })
// 用户列表
if (this.loading) {
LoadingProgress()
.width(50)
.height(50)
} else {
List({ space: 12 }) {
ForEach(this.users, (user: any) => {
ListItem() {
UserItem({
user: user,
onDelete: () => {
this.deleteUser(user.id);
}
})
}
})
}
.layoutWeight(1)
}
}
.width('100%')
.height('100%')
.padding(20)
.backgroundColor('#F5F5F5')
}
}
@Component
struct UserItem {
@Prop user: any;
@Prop onDelete: () => void;
build() {
Row({ space: 15 }) {
Column({ space: 5 }) {
Text(this.user.name)
.fontSize(16)
.fontWeight(FontWeight.Bold)
Text(this.user.email)
.fontSize(14)
.fontColor('#666666')
Text(`年龄:${this.user.age}`)
.fontSize(12)
.fontColor('#999999')
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
Button('删除')
.width(80)
.height(36)
.fontSize(14)
.backgroundColor('#FF3B30')
.onClick(() => {
this.onDelete();
})
}
.width('100%')
.padding(16)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({ radius: 4, color: '#10000000' })
}
}
四、文件存储
对于需要存储大型文件或自定义格式的数据,可以使用文件系统API。
4.1 文件管理类
typescript
import fs from '@ohos.file.fs';
import fileIo from '@ohos.fileio';
class FileManager {
// 获取应用文件目录
private getFilesDir(context: any): string {
return context.filesDir;
}
// 获取缓存目录
private getCacheDir(context: any): string {
return context.cacheDir;
}
// 检查文件是否存在
async fileExists(context: any, filePath: string): Promise<boolean> {
try {
await fileIo.access(filePath);
return true;
} catch {
return false;
}
}
// 写入文本文件
async writeTextFile(context: any, fileName: string, content: string): Promise<boolean> {
const filePath = `${this.getFilesDir(context)}/${fileName}`;
try {
const file = await fileIo.open(filePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
await fileIo.write(file.fd, content);
await fileIo.close(file.fd);
return true;
} catch (error) {
console.error('写入文件失败:', error);
return false;
}
}
// 读取文本文件
async readTextFile(context: any, fileName: string): Promise<string> {
const filePath = `${this.getFilesDir(context)}/${fileName}`;
try {
const file = await fileIo.open(filePath, fileIo.OpenMode.READ_ONLY);
const stat = await fileIo.stat(filePath);
const buffer = new ArrayBuffer(stat.size);
await fileIo.read(file.fd, buffer);
await fileIo.close(file.fd);
const textDecoder = new util.TextDecoder('utf-8');
return textDecoder.decode(buffer);
} catch (error) {
console.error('读取文件失败:', error);
return '';
}
}
// 保存JSON数据
async saveJson(context: any, fileName: string, data: any): Promise<boolean> {
const jsonString = JSON.stringify(data, null, 2);
return this.writeTextFile(context, fileName, jsonString);
}
// 读取JSON数据
async loadJson<T = any>(context: any, fileName: string): Promise<T | null> {
const content = await this.readTextFile(context, fileName);
if (!content) return null;
try {
return JSON.parse(content) as T;
} catch (error) {
console.error('解析JSON失败:', error);
return null;
}
}
// 保存图片到缓存
async saveImageToCache(context: any, imageUrl: string, imageData: ArrayBuffer): Promise<string> {
const cacheDir = this.getCacheDir(context);
const fileName = `${Date.now()}_${imageUrl.split('/').pop()}`;
const filePath = `${cacheDir}/${fileName}`;
try {
const file = await fileIo.open(filePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
await fileIo.write(file.fd, imageData);
await fileIo.close(file.fd);
return filePath;
} catch (error) {
console.error('保存图片失败:', error);
return '';
}
}
// 获取缓存大小
async getCacheSize(context: any): Promise<number> {
const cacheDir = this.getCacheDir(context);
try {
const dir = await fileIo.opendir(cacheDir);
let totalSize = 0;
let dirent = await dir.read();
while (dirent) {
const filePath = `${cacheDir}/${dirent.name}`;
const stat = await fileIo.stat(filePath);
totalSize += stat.size;
dirent = await dir.read();
}
await dir.close();
return totalSize;
} catch (error) {
console.error('获取缓存大小失败:', error);
return 0;
}
}
// 清空缓存
async clearCache(context: any): Promise<boolean> {
const cacheDir = this.getCacheDir(context);
try {
const dir = await fileIo.opendir(cacheDir);
let dirent = await dir.read();
while (dirent) {
const filePath = `${cacheDir}/${dirent.name}`;
await fileIo.unlink(filePath);
dirent = await dir.read();
}
await dir.close();
return true;
} catch (error) {
console.error('清空缓存失败:', error);
return false;
}
}
}
export const fileManager = new FileManager();
4.2 文件操作界面
typescript
@Entry
@Component
struct FileManagerPage {
@State notes: string = '';
@State cacheSize: string = '0 KB';
@State loading: boolean = false;
private context = getContext(this);
async aboutToAppear() {
this.loadNotes();
this.loadCacheSize();
}
async loadNotes() {
const savedNotes = await fileManager.readTextFile(this.context, 'notes.txt');
this.notes = savedNotes || '';
}
async saveNotes() {
const success = await fileManager.writeTextFile(this.context, 'notes.txt', this.notes);
if (success) {
prompt.showToast({ message: '保存成功' });
}
}
async loadCacheSize() {
this.loading = true;
const sizeInBytes = await fileManager.getCacheSize(this.context);
this.cacheSize = this.formatFileSize(sizeInBytes);
this.loading = false;
}
async clearAllCache() {
const success = await fileManager.clearCache(this.context);
if (success) {
prompt.showToast({ message: '缓存已清除' });
this.loadCacheSize();
}
}
private formatFileSize(bytes: number): string {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
build() {
Column({ space: 20 }) {
Text('文件管理')
.fontSize(24)
.fontWeight(FontWeight.Bold)
// 笔记编辑器
Column({ space: 12 }) {
Text('个人笔记')
.fontSize(18)
.fontWeight(FontWeight.Medium)
TextArea({ placeholder: '请输入笔记内容...' })
.width('100%')
.height(200)
.value(this.notes)
.onChange((value: string) => {
this.notes = value;
})
Button('保存笔记')
.width('100%')
.height(50)
.onClick(() => {
this.saveNotes();
})
}
.padding(20)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({ radius: 4, color: '#10000000' })
// 缓存管理
Column({ space: 12 }) {
Text('缓存管理')
.fontSize(18)
.fontWeight(FontWeight.Medium)
Row() {
Text('缓存大小:')
.fontSize(16)
if (this.loading) {
LoadingProgress()
.width(20)
.height(20)
} else {
Text(this.cacheSize)
.fontSize(16)
.fontColor('#007DFF')
}
}
Button('清除缓存')
.width('100%')
.height(50)
.backgroundColor('#FF9500')
.onClick(() => {
this.clearAllCache();
})
}
.padding(20)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({ radius: 4, color: '#10000000' })
}
.width('100%')
.height('100%')
.padding(20)
.backgroundColor('#F5F5F5')
}
}
五、数据加密与安全
对于敏感数据,需要进行加密存储。
5.1 数据加密工具
typescript
import cryptoFramework from '@ohos.security.cryptoFramework';
class CryptoManager {
// 生成密钥
async generateKey(): Promise<string> {
try {
const symKeyGenerator = cryptoFramework.createSymKeyGenerator('AES256');
const symKey = await symKeyGenerator.generateSymKey();
const keyData = await symKey.getEncoded();
// 转换为base64字符串
const base64Key = this.arrayBufferToBase64(keyData.data);
return base64Key;
} catch (error) {
console.error('生成密钥失败:', error);
throw error;
}
}
// 加密数据
async encrypt(text: string, keyBase64: string): Promise<string> {
try {
const keyData = this.base64ToArrayBuffer(keyBase64);
const symKeyGenerator = cryptoFramework.createSymKeyGenerator('AES256');
const symKey = await symKeyGenerator.convertKey({ data: keyData });
const cipher = cryptoFramework.createCipher('AES256|GCM|PKCS7');
await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, null);
const input = { data: this.stringToArrayBuffer(text) };
const encrypted = await cipher.doFinal(input);
return this.arrayBufferToBase64(encrypted.data);
} catch (error) {
console.error('加密失败:', error);
throw error;
}
}
// 解密数据
async decrypt(encryptedBase64: string, keyBase64: string): Promise<string> {
try {
const keyData = this.base64ToArrayBuffer(keyBase64);
const encryptedData = this.base64ToArrayBuffer(encryptedBase64);
const symKeyGenerator = cryptoFramework.createSymKeyGenerator('AES256');
const symKey = await symKeyGenerator.convertKey({ data: keyData });
const cipher = cryptoFramework.createCipher('AES256|GCM|PKCS7');
await cipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, symKey, null);
const input = { data: encryptedData };
const decrypted = await cipher.doFinal(input);
return this.arrayBufferToString(decrypted.data);
} catch (error) {
console.error('解密失败:', error);
throw error;
}
}
// 工具方法
private arrayBufferToBase64(buffer: ArrayBuffer): string {
let binary = '';
const bytes = new Uint8Array(buffer);
for (let i = 0; i < bytes.byteLength; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
}
private base64ToArrayBuffer(base64: string): ArrayBuffer {
const binary = atob(base64);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
return bytes.buffer;
}
private stringToArrayBuffer(str: string): ArrayBuffer {
const encoder = new TextEncoder();
return encoder.encode(str).buffer;
}
private arrayBufferToString(buffer: ArrayBuffer): string {
const decoder = new TextDecoder('utf-8');
return decoder.decode(buffer);
}
}
export const cryptoManager = new CryptoManager();
5.2 安全存储示例
typescript
@Entry
@Component
struct SecureStoragePage {
@State secretKey: string = '';
@State plainText: string = '';
@State encryptedText: string = '';
@State decryptedText: string = '';
@State loading: boolean = false;
async generateKey() {
this.loading = true;
try {
this.secretKey = await cryptoManager.generateKey();
await preferencesManager.set('secret_key', this.secretKey);
prompt.showToast({ message: '密钥已生成并保存' });
} catch (error) {
console.error('生成密钥失败:', error);
}
this.loading = false;
}
async loadKey() {
this.secretKey = (await preferencesManager.get('secret_key', '')) as string;
}
async encryptData() {
if (!this.secretKey) {
prompt.showToast({ message: '请先生成或加载密钥' });
return;
}
if (!this.plainText) {
prompt.showToast({ message: '请输入要加密的文本' });
return;
}
this.loading = true;
try {
this.encryptedText = await cryptoManager.encrypt(this.plainText, this.secretKey);
prompt.showToast({ message: '加密成功' });
} catch (error) {
console.error('加密失败:', error);
prompt.showToast({ message: '加密失败' });
}
this.loading = false;
}
async decryptData() {
if (!this.secretKey) {
prompt.showToast({ message: '请先加载密钥' });
return;
}
if (!this.encryptedText) {
prompt.showToast({ message: '请输入要解密的文本' });
return;
}
this.loading = true;
try {
this.decryptedText = await cryptoManager.decrypt(this.encryptedText, this.secretKey);
prompt.showToast({ message: '解密成功' });
} catch (error) {
console.error('解密失败:', error);
prompt.showToast({ message: '解密失败' });
}
this.loading = false;
}
aboutToAppear() {
preferencesManager.init(getContext(this));
this.loadKey();
}
build() {
Column({ space: 20 }) {
Text('安全存储')
.fontSize(24)
.fontWeight(FontWeight.Bold)
// 密钥管理
Column({ space: 12 }) {
Text('密钥管理')
.fontSize(18)
.fontWeight(FontWeight.Medium)
Row({ space: 10 }) {
Button('生成密钥')
.width(120)
.height(40)
.onClick(() => {
this.generateKey();
})
Button('加载密钥')
.width(120)
.height(40)
.onClick(() => {
this.loadKey();
})
}
if (this.secretKey) {
Text('密钥已加载')
.fontSize(14)
.fontColor('#34C759')
}
}
.padding(20)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({ radius: 4, color: '#10000000' })
// 加密区域
Column({ space: 12 }) {
Text('加密')
.fontSize(18)
.fontWeight(FontWeight.Medium)
TextInput({ placeholder: '请输入要加密的文本' })
.width('100%')
.height(80)
.value(this.plainText)
.onChange((value: string) => {
this.plainText = value;
})
Button('加密')
.width('100%')
.height(50)
.onClick(() => {
this.encryptData();
})
if (this.encryptedText) {
Text('加密结果:')
.fontSize(14)
Text(this.encryptedText)
.fontSize(12)
.fontColor('#666666')
.maxLines(3)
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
}
.padding(20)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({ radius: 4, color: '#10000000' })
// 解密区域
Column({ space: 12 }) {
Text('解密')
.fontSize(18)
.fontWeight(FontWeight.Medium)
TextInput({ placeholder: '请输入要解密的文本' })
.width('100%')
.height(80)
.value(this.encryptedText)
.onChange((value: string) => {
this.encryptedText = value;
})
Button('解密')
.width('100%')
.height(50)
.onClick(() => {
this.decryptData();
})
if (this.decryptedText) {
Text('解密结果:')
.fontSize(14)
Text(this.decryptedText)
.fontSize(14)
.fontColor('#333333')
}
}
.padding(20)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({ radius: 4, color: '#10000000' })
if (this.loading) {
LoadingProgress()
.width(50)
.height(50)
}
}
.width('100%')
.height('100%')
.padding(20)
.backgroundColor('#F5F5F5')
}
}
六、存储方案选择指南
| 存储方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| Preferences | 用户设置、登录状态、简单配置 | 使用简单、性能好 | 不适合大量数据、复杂查询 |
| 关系型数据库 | 用户数据、消息记录、复杂数据结构 | 支持复杂查询、事务 | 使用相对复杂、需要SQL知识 |
| 文件存储 | 大文件、图片、文档、自定义格式数据 | 灵活、适合大量数据 | 需要手动管理文件、无内置查询功能 |
| 加密存储 | 敏感数据(密码、支付信息) | 安全性高 | 性能开销大、需要密钥管理 |
七、最佳实践
7.1 分层存储策略
typescript
class StorageStrategy {
// 内存缓存(最快)
private memoryCache = new Map<string, any>();
// Preferences(中等速度)
private preferences: PreferencesManager;
// 数据库/文件(最慢,但持久化)
private database: DatabaseManager;
private fileManager: FileManager;
constructor() {
this.preferences = new PreferencesManager();
this.database = new DatabaseManager();
this.fileManager = new FileManager();
}
// 获取数据(多层缓存)
async getData<T>(key: string): Promise<T | null> {
// 1. 检查内存缓存
if (this.memoryCache.has(key)) {
return this.memoryCache.get(key);
}
// 2. 检查Preferences
const prefData = await this.preferences.get(key);
if (prefData) {
this.memoryCache.set(key, prefData);
return prefData as T;
}
// 3. 检查数据库/文件
// ... 根据key的类型选择不同的存储方式
return null;
}
}
7.2 数据同步策略
typescript
class DataSyncManager {
// 同步本地和远程数据
async syncData<T>(
localKey: string,
remoteFetch: () => Promise<T>,
shouldUpdate: (local: T, remote: T) => boolean
): Promise<T> {
// 1. 从本地获取数据
const localData = await this.getLocalData<T>(localKey);
// 2. 从远程获取数据
let remoteData: T;
try {
remoteData = await remoteFetch();
} catch (error) {
// 网络失败,返回本地数据
console.warn('网络请求失败,使用本地数据');
return localData;
}
// 3. 比较数据,决定是否更新
if (!localData || shouldUpdate(localData, remoteData)) {
await this.saveLocalData(localKey, remoteData);
return remoteData;
}
return localData;
}
}
八、总结与下期预告
8.1 本文要点回顾
-
Preferences:轻量级键值存储,适合简单配置
-
关系型数据库:复杂数据存储,支持SQL查询
-
文件存储:大文件和自定义格式数据存储
-
数据加密:敏感数据的安全存储
-
存储策略:如何根据场景选择合适的存储方案
8.2 下期预告:《鸿蒙开发之:服务卡片开发实战》
下篇文章将深入讲解:
-
服务卡片的基本概念和使用场景
-
卡片布局和样式设计
-
卡片数据更新和交互
-
卡片配置和部署
-
实战:创建各种类型的服务卡片
动手挑战
任务1:实现备忘录应用
要求:
-
使用数据库存储备忘录数据
-
支持备忘录的增删改查
-
支持备忘录分类和标签
-
实现数据备份和恢复功能
任务2:实现图片收藏应用
要求:
-
使用文件系统保存图片
-
使用数据库保存图片元数据
-
支持图片的分类和搜索
-
实现图片加密存储
任务3:实现数据同步框架
要求:
-
支持本地和远程数据同步
-
实现冲突解决策略
-
支持离线编辑和自动同步
-
实现数据版本控制
将你的代码分享到评论区,我会挑选优秀实现进行详细点评!
常见问题解答
Q:Preferences和数据库有什么区别?
A:Preferences适合存储简单的键值对,如用户设置;数据库适合存储结构化数据,支持复杂查询。
Q:如何选择文件存储还是数据库存储?
A:如果是结构化数据且需要查询,用数据库;如果是文件、图片或自定义格式,用文件存储。
Q:加密存储会影响性能吗?
A:会有一定性能影响,但对于敏感数据,安全比性能更重要。可以对关键数据进行加密,非敏感数据明文存储。
Q:如何备份用户数据?
A:可以将数据库或重要文件打包,保存到云端或设备外部存储。
PS:现在HarmonyOS应用开发者认证正在做活动,初级和高级都可以免费学习及考试,赶快加入班级学习啦:【注意,考试只能从此唯一链接进入】
https://developer.huawei.com/consumer/cn/training/classDetail/33f85412dc974764831435dc1c03427c?type=1?ha_source=hmosclass&ha_sourceld=89000248
版权声明:本文为《鸿蒙开发系列》第6篇,原创文章,转载请注明出处。
标签:#HarmonyOS #鸿蒙开发 #本地存储 #数据库 #文件操作 #数据加密 #华为开发者
更多推荐




所有评论(0)