鸿蒙preferences单多例使用,本地存储类

CustomFilePersistence 类操作文档

一、文档概述

本文档旨在详细说明 CustomFilePersistence 类的功能、使用方法、API 接口及注意事项。该类基于鸿蒙(HarmonyOS)的 preferences 组件封装,提供了面向 Map 结构的本地数据持久化能力,支持单例模式(默认存储地址)和多实例模式(自定义存储地址),可实现数据的添加、查询、删除、清空等操作,适用于鸿蒙应用的轻量级本地数据存储场景。

二、环境依赖

  1. 系统版本:支持 HarmonyOS API Version 12 及以上版本。

  2. 依赖组件

  • 鸿蒙系统内置 @ohos.data.preferences 模块(用于本地数据存储)。

  • 鸿蒙系统内置 @ohos.app.ability.common 模块(用于获取应用上下文)。

  • 自定义日志工具类 MyLog(需根据实际项目路径调整导入,用于日志打印CustomFilePersistence看日志)。

三、类核心特性

  1. 实例管理:支持默认单例实例(固定存储地址)和自定义多实例(不同存储地址,通过数据库名区分),满足多模块独立存储需求。

  2. 数据结构 :基于 Map 结构封装,简化键值对数据的批量操作,同时兼容 preferences 组件的对象存储格式。

  3. 类型安全 :采用泛型设计,避免 any/unknown 类型,符合 ArkTS 开发规范,降低类型错误风险。

  4. 日志支持 :集成 MyLog 工具,打印数据操作日志(保存、删除、异常等),便于开发调试。

四、使用步骤

4.1 导入

在需要使用数据持久化功能的文件中,导入 CustomFilePersistence 类,同时确保依赖类路径正确:

ohpm install @zyl/file_persistence_manager

4.2 实例获取

该类提供两种实例获取方式,分别适用于不同存储场景:

4.2.1 获取默认单例实例

适用于全局统一存储场景,默认数据库名为 DEFAULT_PREFERENCES,整个应用生命周期内仅创建一个实例:

typescript 复制代码
// 获取默认单例实例
const defaultPersistence = CustomFilePersistence.getInstance;

4.2.2 创建自定义实例

适用于多模块独立存储场景,可指定自定义数据库名(对应不同存储地址),每次调用都会创建新实例:

typescript 复制代码
// 创建自定义实例(指定数据库名)
const customPersistence = CustomFilePersistence.createInstance('USER_DATA'); // 数据名自定义

// 创建自定义实例(使用默认数据库名 STORAGE_KEY) = CustomFilePersistence.getInstance;
// const defaultNamePersistence = CustomFilePersistence.createInstance();

4.3 核心操作示例

以下示例基于自定义实例演示各类数据操作,默认单例实例用法完全一致。

4.3.1 添加/更新数据

通过 addOrSetData 方法添加新数据,若数据键名已存在则自动更新:

typescript 复制代码
// 添加字符串类型数据
customPersistence.addOrSetData('userName', 'ZhangSan');

// 添加对象类型数据
interface OrderPrice {
    price: number;
    status: string;
}
this.orderPrefs.addOrSetData('order_1001', { price: 99.9, status: 'pending' } as OrderPrice);

4.3.2 查询数据

通过 getData 方法查询指定键名的数据,支持泛型指定返回类型:

typescript 复制代码
// 查询字符串类型数据
const userName = customPersistence.getData<string>('userName');
console.log('用户姓名:', userName); // 输出:用户姓名:ZhangSan

// 查询对象类型数据
const userInfo = customPersistence.getData<UserInfo>('userInfo');
console.log('用户信息:', userInfo);

4.3.3 检查数据是否存在

通过 hasData 方法判断指定键名的数据是否存在:

typescript 复制代码
const hasUserName = customPersistence.hasData('userName');
if (hasUserName) {
  console.log('userName 字段已存在');
} else {
  console.log('userName 字段不存在');
}

4.3.4 删除数据

通过 deleteData 方法删除指定键名的数据,返回删除结果(成功为 true,失败为 false):

typescript 复制代码
const deleteResult = customPersistence.deleteData('userAge');
if (deleteResult) {
  console.log('userAge 字段删除成功');
} else {
  console.log('userAge 字段不存在,删除失败');
}

4.3.5 批量获取数据

通过 getAllMap 方法获取当前数据库中所有数据,返回 Map 结构:

typescript 复制代码
MyLog.log(CustomFilePersistence.getInstance.getDbName())
const allData =  CustomFilePersistence.getInstance.getAllMap<number>();
// 遍历 Map 数据
allData.forEach((value, key) => {
  console.log(`键:${key},值:${JSON.stringify(value.value)}`);
});

4.3.6 清空数据库

通过 clearAll 方法清空当前实例对应的数据库所有数据(仅影响当前数据库,不影响其他实例):

typescript 复制代码
customPersistence.clearAll();

4.3.7 获取数据库名

通过 getDbName 方法获取当前实例对应的数据库名,便于调试和管理:

typescript 复制代码
const dbName = customPersistence.getDbName();
console.log('当前数据库名:', dbName); // 输出:当前数据库名:USER_DATA

4.4 完整组件案例(已验证通过)

以下为两个完整的鸿蒙组件案例,分别演示默认单例实例和自定义实例的全场景使用,包含界面交互按钮及数据操作逻辑,均已实际验证通过。

4.4.1 主组件(PersistenceDemo):默认实例操作

该组件演示通过默认单例实例操作数据,涵盖新增、修改、删除、查询、清空等核心功能,绑定界面按钮触发交互。

ts 复制代码
import { CustomFilePersistence } from "../src/main/ets/CustomFilePersistence"
import { MyLog } from "../src/main/ets/MyLog"
import { CustomPer } from "./CustomPer";


@Component
export struct PersistenceDemo {
  @State isShowLoading2: boolean = false
   orderPrefs:CustomFilePersistence = CustomFilePersistence.createInstance('ORDER_PREFERENCES'); // 订单专用数据库
  build() {
    Scroll() {
      Column(){
        Button('默认的初始化清楚').onClick(()=>{
          CustomFilePersistence.getInstance.clearAll()
        })
        Button('默认的新增或者修改一个').onClick(()=>{
          // /data/app/el2/100/base/com.leran.huawei/haps/entry/preferences/STORAGE_KEY
          CustomFilePersistence.getInstance.addOrSetData('key1', 1)
        })

        Button('默认的删除一个').onClick(()=>{
          CustomFilePersistence.getInstance.deleteData('key1')
        })
        Button('默认的删除所有').onClick(()=>{
          CustomFilePersistence.getInstance.clearAll()
        })
        Button('默认的查询一个').onClick(()=>{
          // CustomFilePersistence().addOrSetData<number>('key1', 1)
         const num =  CustomFilePersistence.getInstance.getData<number>('key1')
          MyLog.log('num1',JSON.stringify(num))

        })
        // Button('默认的是否存在').onClick(()=>{
        //   // CustomFilePersistence().addOrSetData<number>('key1', 1)
        //   const bol =  CustomFilePersistence.getInstance.hasData('key1')
        //   MyLog.log(bol?'存在':'不存在')
        // })
        // Button('默认的删除所有').onClick(()=>{
        //   // CustomFilePersistence().addOrSetData<number>('key1', 1)
        //   CustomFilePersistence.getInstance.clearAll()
        // })

        Button('获取所有其他').onClick(()=>{
          // CustomFilePersistence().addOrSetData<number>('key1', 1)
          MyLog.log(CustomFilePersistence.getInstance.getDbName())
          const allData =  CustomFilePersistence.getInstance.getAllMap<number>();
          // 遍历 Map 数据
          allData.forEach((value, key) => {
            MyLog.log(`键:${key},值:${JSON.stringify(value.value)}`);
          });
        })

      }
    }
    .scrollBar(BarState.Auto)
    .scrollBarColor(Color.Gray) // 滚动条颜色
    .scrollBarWidth(0) // 滚动条宽度
    .friction(0.6)
    .edgeEffect(EdgeEffect.None) //设置滑动效果 //Fade
    .width('100%')
    .id('exampleIndex')
  }
}

4.4.2 子组件(CustomPer):自定义创建实例操作

该组件演示通过自定义实例(订单专用数据库)操作数据,支持基础类型和自定义对象类型存储,与默认实例数据相互隔离。

ts 复制代码
import { CustomFilePersistence } from "../src/main/ets/CustomFilePersistence"
import { MyLog } from "../src/main/ets/MyLog"

// { price: 99.9, status: 'pending' }
interface OrderPrice {
  price: number;
  status: string;
}
@Component
export struct CustomPer {
  orderPrefs:CustomFilePersistence = CustomFilePersistence.createInstance('ORDER_PREFERENCES'); // 订单专用数据库
  build() {
    Scroll() {
      Column(){
        Button('自定义持久化名称初始化清楚').onClick(()=>{
          this.orderPrefs.clearAll()
        })
        Button('自定义持久化名称新增或者修改一个').onClick(()=>{
          // /data/app/el2/100/base/com.leran.huawei/haps/entry/preferences/STORAGE_KEY
          this.orderPrefs.addOrSetData('key1', 1)
        })
        Button('新增一个自定义的文件名').onClick(()=>{
          // /data/app/el2/100/base/com.leran.huawei/haps/entry/preferences/STORAGE_KEY
          this.orderPrefs.addOrSetData('order_1001', { price: 99.9, status: 'pending' } as OrderPrice);
        })

        Button('自定义持久化名称删除一个').onClick(()=>{
          this.orderPrefs.deleteData('key1')
        })
        Button('自定义持久化名称删除所有').onClick(()=>{
          this.orderPrefs.clearAll()
        })
        Button('自定义持久化名称的查询一个').onClick(()=>{
          // CustomFilePersistence().addOrSetData<number>('key1', 1)
          const num =  this.orderPrefs.getData<number>('key1')
          MyLog.log('num1',JSON.stringify(num))

          const num1 =  this.orderPrefs.getData<OrderPrice>('order_1001')
          MyLog.log('num1',JSON.stringify(num1))

        })
        Button('自定义持久化名称的是否存在').onClick(()=>{
          // CustomFilePersistence().addOrSetData<number>('key1', 1)
          const bol =  this.orderPrefs.hasData('key1')
          MyLog.log(bol?'存在':'不存在')
        })
        Button('自定义持久化名称的删除所有').onClick(()=>{
          // CustomFilePersistence().addOrSetData<number>('key1', 1)
          this.orderPrefs.clearAll()
        })
        Button('获取所有其他').onClick(()=>{
          // CustomFilePersistence().addOrSetData<number>('key1', 1)
          MyLog.log(this.orderPrefs.getDbName())
          const allData =  this.orderPrefs.getAllMap<number|OrderPrice>();
          // 遍历 Map 数据
          allData.forEach((value, key) => {
            MyLog.log(`键:${key},值:${JSON.stringify(value.value)}`);
          });
        })

      }
    }
    .scrollBar(BarState.Auto)
    .scrollBarColor(Color.Gray) // 滚动条颜色
    .scrollBarWidth(0) // 滚动条宽度
    .friction(0.6)
    .edgeEffect(EdgeEffect.None) //设置滑动效果 //Fade
    .width('100%')
    .id('exampleIndex')
  }
}

案例说明:两个组件分别操作默认实例(数据库名:DEFAULT_PREFERENCES)和自定义实例(数据库名:ORDER_PREFERENCES),数据相互独立无干扰。支持基础类型(number)和自定义对象类型(OrderPrice)存储,所有按钮点击逻辑均已验证通过,可直接集成到鸿蒙应用中使用。

五、API 详细说明

5.1 构造函数

构造函数 参数说明 备注
constructor(dbName: string = 'STORAGE_KEY') dbName:数据库名称,对应自定义存储地址,默认值为 'STORAGE_KEY' 私有构造,外部需通过 getInstancecreateInstance 获取实例

5.2 静态方法

方法名 返回值 参数说明 功能描述
static get getInstance(): CustomFilePersistence CustomFilePersistence 获取默认单例实例,默认数据库名为 'DEFAULT_PREFERENCES',仅初始化一次
static createInstance(dbName?: string): CustomFilePersistence CustomFilePersistence dbName:可选,数据库名称,默认值为 'STORAGE_KEY' 创建自定义实例,每次调用返回新实例,支持多独立存储

5.3 实例方法

方法名 返回值 参数说明 功能描述
getAllMap<T>(): Map<string, CustomPersistenceClass<T>> Map<string, CustomPersistenceClass<T>> T:泛型,指定存储数据的值类型 批量获取当前数据库所有数据,转换为 Map 结构返回,键为数据名,值为 CustomPersistenceClass 实例
addOrSetData<T>(name: string, value: T): void void name:数据键名;T:泛型,数据值类型;value:数据值 添加或更新数据,若 name 已存在则覆盖原有值,自动封装为 CustomPersistenceClass 实例存储
deleteData(name: string): boolean boolean name:需删除的数据键名 删除指定键名的数据,删除成功返回 true,数据不存在返回 false,删除后自动同步到本地
`getData(name: string): T undefined` `T undefined`
hasData(name: string): boolean boolean name:需检查的数据键名 判断指定键名的数据是否存在,存在返回 true,否则返回 false
clearAll(): void void 清空当前数据库所有数据,同步到本地,打印操作日志(成功/失败)
getDbName(): string string 返回当前实例对应的数据库名称

5.4 私有方法

方法名 功能描述
saveMap<T>(map: Map<string, CustomPersistenceClass<T>>): void 将 Map 结构数据转换为普通对象,存储到 preferences 中,并触发数据刷新同步

六、注意事项

  1. 上下文获取说明 :当前构造函数通过 getContext(this) 获取 UIAbilityContext,若需在非 UIAbility 场景(如 ServiceAbility)使用,需调整上下文获取方式,可将上下文作为构造函数参数传入(修改构造函数为 constructor(dbName: string = 'STORAGE_KEY', context: common.UIAbilityContext))。

  2. 数据类型限制:存储的数据需支持 JSON 序列化/反序列化(如字符串、数字、对象、数组等),不支持函数、Symbol 等非可序列化类型。

  3. 实例独立性 :通过 createInstance 创建的不同实例,对应不同的数据库文件(以 dbName 区分),数据相互独立,清空一个实例的数据库不会影响其他实例。

  4. 日志依赖MyLog 类需自行实现日志打印逻辑(如控制台输出、文件日志等),若无需日志可删除相关调用代码。

  5. 异常处理clearAll 方法已包含异常捕获,其他方法(如 addOrSetDatadeleteData)依赖 preferences 的同步接口,若需增强异常处理,可在对应方法中添加 try-catch 块。

  6. 泛型使用:查询和添加数据时,建议显式指定泛型类型,确保类型安全,避免运行时类型错误。

七、常见问题

Q1:数据存储后重启应用丢失?

A1:确保每个实例的 dbName 唯一,不同 dbName 对应不同的存储文件,数据相互隔离。若 dbName 重复,会导致实例操作同一数据库,出现数据干扰。

Q2:查询数据时返回 undefined

A2:可能原因:1. 数据键名错误;2. 数据未成功存储(可查看 MyLog 日志确认);3. 泛型类型指定错误,导致数据解析异常。

(注:文档部分内容可能由 AI 生成)

🙏内容有问题联系纠正,或者什么意见提供联系Q:867374269

相关推荐
IvanCodes2 小时前
[鸿蒙2025领航者闯关] 共享终端的隐形守护者:基于 HarmonyOS 6 的全链路隐私闭环实战
华为·harmonyos·鸿蒙
爱丽_2 小时前
MyBatis事务管理与缓存机制详解
数据库·缓存·mybatis
一条大祥脚4 小时前
25.12.30
数据库·redis·缓存
芒鸽7 小时前
鸿蒙PC上FFmpeg+Electron的Encode Smoke(P2) 排错实录:从“无法播放/时长为 0”到“保留画面且转完整时长”
ffmpeg·electron·harmonyos
2501_944449089 小时前
帮助中心页面 Cordova&OpenHarmony 混合开发实战
harmonyos
航Hang*9 小时前
第二章:网络系统建设与运维(中级)——华为设备基本命令
运维·计算机网络·华为·ensp·交换机
攻心的子乐9 小时前
redis 使用Pipelined 管道命令批量操作 减少网络操作次数
数据库·redis·缓存
北方的流星9 小时前
华为PPPoE协议的配置
运维·网络·华为
Channon_9 小时前
专题四:内存战场的无声战役——压缩、共享与空间复用
缓存·嵌入式·空间复用