# [特殊字符] 零基础学 ArkUI 数据持久化(专题三):5 种存储方案深度对比

💾 零基础学 ArkUI 数据持久化(专题三):5 种存储方案深度对比

博主说: 用户的数据|第一行代码|App 重启就不见了?那这个 App 基本就废了。数据持久化是每个 App 的刚需------不管是用户设置、笔记内容、缓存图片还是离线数据库。HarmonyOS 提供了 5 种持久化方案,今天一次讲清楚「什么时候用哪个」以及「怎么写」。


📊 5 种方案总览

方案 数据类型 读写速度 存储限制 适用场景
🥇 PersistentStorage 简单 KV(字符串/数字/布尔) 极快 少量 用户设置、主题、开关状态
🥈 preferences KV 键值对 中等 笔记内容、草稿、配置
🥉 SQLite (relationalStore) 结构化关系数据 通讯录、订单、复杂查询
fileIo 文件存储 二进制/文本文件 图片缓存、日志、导出文件
分布式数据库 跨设备同步数据 多设备协同、云同步

⚙️ 运行环境

项目 要求
DevEco Studio 5.0.3.800+
HarmonyOS SDK API 12+

🛠️ 5 种方案代码实战

🎯 方案 1:PersistentStorage --- 最简单,适合开关/主题

typescript 复制代码
@Entry
@Component
struct Demo_PersistentStorage {
  // PersistentStorage 自动将变量同步到磁盘
  @StorageLink('isDarkMode') isDarkMode: boolean = false;
  @StorageLink('themeColor') themeColor: string = '#007AFF';
  @StorageLink('fontSize') fontSize: number = 16;

  build() {
    Column() {
      Text('App 设置').fontSize(24).fontWeight(FontWeight.Bold)

      Row() {
        Text('暗黑模式')
        Toggle({ type: ToggleType.Switch, isOn: this.isDarkMode })
          .onChange((v: boolean) => {
            this.isDarkMode = v; // 自动持久化!
          })
      }.justifyContent(FlexAlign.SpaceBetween).width('90%').padding(12)

      Row() {
        Text('主题色')
        Select([{ value: '#007AFF' }, { value: '#FF3B30' }, { value: '#34C759' }])
          .value(this.themeColor)
          .onSelect((_, val: string) => { this.themeColor = val; })
      }.width('90%').padding(12)

      Row() {
        Text('字体大小')
        Slider({ value: this.fontSize, min: 12, max: 24, step: 2 })
          .onChange((v: number) => { this.fontSize = v; })
      }.width('90%').padding(12)

      Text('💡 关闭 App 重新打开,所有设置依然保留!')
        .fontSize(14).fontColor('#999').margin({ top: 20 })
    }
    .width('100%').padding(16)
  }
}

原理: @StorageLink 在 App 启动时自动从 PersistentStorage 加载数据,修改时自动写回------零手写存储代码。


🎯 方案 2:preferences --- 手动 KV 存储,灵活可控

typescript 复制代码
import preferences from '@ohos.data.preferences';

@Entry
@Component
struct Demo_Preferences {
  @State notes: string[] = [];
  private pref!: preferences.Preferences;

  aboutToAppear() {
    this.initPref();
  }

  async initPref() {
    const ctx = getContext(this);
    this.pref = await preferences.getPreferences(ctx, 'note_store');
    await this.loadNotes();
  }

  async loadNotes() {
    const json = this.pref.get('notes', '[]');
    this.notes = JSON.parse(json as string);
  }

  async saveNotes() {
    await this.pref.put('notes', JSON.stringify(this.notes));
    await this.pref.flush(); // 立即写盘
  }

  async addNote(text: string) {
    this.notes.unshift(text);
    await this.saveNotes();
  }

  async deleteNote(idx: number) {
    this.notes.splice(idx, 1);
    await this.saveNotes();
  }

  build() {
    Column() {
      Button('➕ 添加笔记').onClick(() => { this.addNote('新笔记 ' + Date.now()); })
      List() {
        ForEach(this.notes, (note: string, idx: number) => {
          ListItem() {
            Row() {
              Text(note).layoutWeight(1)
              Button('✕').fontColor('#FF3B30').backgroundColor('transparent')
                .onClick(() => { this.deleteNote(idx as number); })
            }.padding(12)
          }
        })
      }.layoutWeight(1).width('100%')
    }.width('100%').height('100%').padding(16)
  }
}

🎯 方案 3:SQLite (relationalStore) --- 结构化数据搜索引擎

typescript 复制代码
import relationalStore from '@ohos.data.relationalStore';

@Entry
@Component
struct Demo_SQLite {
  private store!: relationalStore.RdbStore;
  @State users: { id: number; name: string; age: number }[] = [];

  aboutToAppear() {
    this.initDB();
  }

  async initDB() {
    const config = {
      name: 'myapp.db',
      securityLevel: relationalStore.SecurityLevel.S1
    };
    this.store = await relationalStore.getRdbStore(getContext(this), config);

    // 建表
    await this.store.executeSql(
      'CREATE TABLE IF NOT EXISTS user (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER)'
    );

    await this.loadUsers();
  }

  async addUser(name: string, age: number) {
    await this.store.insert('user', { name, age });
    await this.loadUsers();
  }

  async loadUsers() {
    const predicates = new relationalStore.RdbPredicates('user');
    predicates.orderByDesc('id');
    const result = await this.store.query(predicates, ['id', 'name', 'age']);

    const list: any[] = [];
    while (result.goToNextRow()) {
      list.push({
        id: result.getLong(result.getColumnIndex('id')),
        name: result.getString(result.getColumnIndex('name')),
        age: result.getLong(result.getColumnIndex('age'))
      });
    }
    this.users = list;
    result.close();
  }

  build() {
    Column() {
      Button('➕ 添加用户').onClick(() => { this.addUser('用户' + Date.now(), 20); })
      List() {
        ForEach(this.users, (u: any) => {
          ListItem() {
            Text(`${u.name} --- ${u.age}岁`).padding(12)
          }
        }, (u: any) => u.id.toString())
      }.layoutWeight(1).width('100%')
    }.width('100%').height('100%').padding(16)
  }
}

🎯 方案 4:fileIo 文件存储 --- 存图片/日志/缓存

typescript 复制代码
import fileIo from '@ohos.file.fs';

async function saveToFile(context: any, filename: string, content: string) {
  const path = context.filesDir + '/' + filename;
  const file = await fileIo.open(path, fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE);
  await fileIo.write(file.fd, content);
  fileIo.close(file);
}

async function readFromFile(context: any, filename: string): Promise<string> {
  const path = context.filesDir + '/' + filename;
  const file = await fileIo.open(path, fileIo.OpenMode.READ_ONLY);
  const buf = new ArrayBuffer(4096);
  const readLen = await fileIo.read(file.fd, buf);
  fileIo.close(file);
  return String.fromCharCode(...new Uint8Array(buf.slice(0, readLen)));
}

🎯 方案 5:分布式数据库 --- 跨设备同步

typescript 复制代码
import distributedKVStore from '@ohos.data.distributedKVStore';

async function setupDistributedDB(context: any) {
  const kvManager = await distributedKVStore.createKVManager({
    bundleName: 'com.example.app',
    context: context
  });
  const kvStore = await kvManager.getKVStore('sync_store', {
    createIfMissing: true,
    encrypt: false,
    backup: false,
    autoSync: true    // 自动同步到其他设备
  });

  // 写入(自动同步到登录了同一账号的其他设备)
  await kvStore.put('key_hello', 'Hello from Device A');

  // 读取
  const value = await kvStore.get('key_hello');
}

📊 方案对比决策树

复制代码
数据需要持久化?
├── 数据量极小(<10个键)?
│   └── ✅ PersistentStorage(@StorageLink 零代码)
├── 数据是 KV 键值对?
│   └── ✅ preferences(手动读写,灵活可控)
├── 数据有结构化关系?
│   └── ✅ SQLite relationalStore(支持 SQL 查询)
├── 数据是文件/二进制?
│   └── ✅ fileIo(图片、日志、导出)
└── 需要跨设备同步?
    └── ✅ 分布式数据库(端云协同)

⚠️ 避坑指南

原因 正确做法
PersistentStorage 数据丢失 只支持基本类型,不支持对象 存 JSON.stringify + JSON.parse
preferences 写入不生效 忘了调用 flush() 每次修改后调用 flush() 立即刷盘
SQLite 打开失败 数据库文件损坏 用事务包裹写入操作
fileIo 路径不对 用了硬编码路径 context.filesDir / cacheDir
分布式数据不同步 没登录华为账号 登录同一华为账号 + 打开 WiFi/蓝牙

🔥 最佳实践

  1. 选型策略 :能用 PersistentStorage 就不上 preferences,能用 preferences 就不上 SQLite
  2. JSON 序列化 :复杂对象用 JSON.stringify/parse 转成字符串存储
  3. 异常处理 :所有存储操作都用 try/catch 包裹
  4. 存储加密 :敏感数据(密码/Token)用 @ohos.security.huks 加密后再存
  5. 定期清理cacheDir 中的缓存文件定期清理,避免撑爆存储
  6. 异步操作 :存储 API 都是异步的,用 async/await 处理

官方文档: HarmonyOS 应用开发文档

相关推荐
●VON1 小时前
AtomGit Flutter鸿蒙客户端:Provider状态管理
flutter·华为·跨平台·harmonyos·鸿蒙
FrameNotWork1 小时前
HarmonyOS6.1 图像分类应用完整实战:从模型到界面
人工智能·分类·数据挖掘·harmonyos
带刺的坐椅1 小时前
SolonCode(编码智能体)支持鸿蒙 PC
java·web·ai编程·harmonyos·soloncode·鸿蒙 pc
Lucky_ldy1 小时前
51单片机的学习终(结合中科协的个人自用笔记)
笔记·学习·51单片机
李二。1 小时前
HarmonyOS NEXT 定时关机工具:从设计到实现的完整技术解析
华为·harmonyos
星幻元宇VR1 小时前
消防教育基地展厅设备【消防知识安全竞赛系统】
人工智能·科技·学习·安全
川石课堂软件测试2 小时前
UI自动化测试|CSS元素定位实践
css·测试工具·ui·fiddler·单元测试·appium·harmonyos
yuegu7772 小时前
HarmonyOS应用<节气通>开发第15篇:学习记录页面
学习·信息可视化·harmonyos