CustomFilePersistence 类操作文档
一、文档概述
本文档旨在详细说明 CustomFilePersistence 类的功能、使用方法、API 接口及注意事项。该类基于鸿蒙(HarmonyOS)的 preferences 组件封装,提供了面向 Map 结构的本地数据持久化能力,支持单例模式(默认存储地址)和多实例模式(自定义存储地址),可实现数据的添加、查询、删除、清空等操作,适用于鸿蒙应用的轻量级本地数据存储场景。
二、环境依赖
-
系统版本:支持 HarmonyOS API Version 12 及以上版本。
-
依赖组件:
-
鸿蒙系统内置
@ohos.data.preferences模块(用于本地数据存储)。 -
鸿蒙系统内置
@ohos.app.ability.common模块(用于获取应用上下文)。 -
自定义日志工具类
MyLog(需根据实际项目路径调整导入,用于日志打印CustomFilePersistence看日志)。
三、类核心特性
-
实例管理:支持默认单例实例(固定存储地址)和自定义多实例(不同存储地址,通过数据库名区分),满足多模块独立存储需求。
-
数据结构 :基于 Map 结构封装,简化键值对数据的批量操作,同时兼容
preferences组件的对象存储格式。 -
类型安全 :采用泛型设计,避免
any/unknown类型,符合 ArkTS 开发规范,降低类型错误风险。 -
日志支持 :集成
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' |
私有构造,外部需通过 getInstance 或 createInstance 获取实例 |
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 中,并触发数据刷新同步 |
六、注意事项
-
上下文获取说明 :当前构造函数通过
getContext(this)获取UIAbilityContext,若需在非 UIAbility 场景(如 ServiceAbility)使用,需调整上下文获取方式,可将上下文作为构造函数参数传入(修改构造函数为constructor(dbName: string = 'STORAGE_KEY', context: common.UIAbilityContext))。 -
数据类型限制:存储的数据需支持 JSON 序列化/反序列化(如字符串、数字、对象、数组等),不支持函数、Symbol 等非可序列化类型。
-
实例独立性 :通过
createInstance创建的不同实例,对应不同的数据库文件(以dbName区分),数据相互独立,清空一个实例的数据库不会影响其他实例。 -
日志依赖 :
MyLog类需自行实现日志打印逻辑(如控制台输出、文件日志等),若无需日志可删除相关调用代码。 -
异常处理 :
clearAll方法已包含异常捕获,其他方法(如addOrSetData、deleteData)依赖preferences的同步接口,若需增强异常处理,可在对应方法中添加try-catch块。 -
泛型使用:查询和添加数据时,建议显式指定泛型类型,确保类型安全,避免运行时类型错误。
七、常见问题
Q1:数据存储后重启应用丢失?
A1:确保每个实例的 dbName 唯一,不同 dbName 对应不同的存储文件,数据相互隔离。若 dbName 重复,会导致实例操作同一数据库,出现数据干扰。
Q2:查询数据时返回 undefined?
A2:可能原因:1. 数据键名错误;2. 数据未成功存储(可查看 MyLog 日志确认);3. 泛型类型指定错误,导致数据解析异常。
(注:文档部分内容可能由 AI 生成)