鸿蒙开发之:本地数据存储方案

34 阅读11分钟

本文字数:约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 { try { await fileIo.access(filePath); return true; } catch { return false; } }

// 写入文本文件 async writeTextFile(context: any, fileName: string, content: string): Promise { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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(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( localKey: string, remoteFetch: () => Promise, shouldUpdate: (local: T, remote: T) => boolean ): Promise { // 1. 从本地获取数据 const localData = await this.getLocalData(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应用开发者认证正在做活动,初级和高级都可以免费学习及考试,赶快加入班级学习啦:【注意,考试只能从此唯一链接进入】 developer.huawei.com/consumer/cn…