鸿蒙应用开发实战【92】— 实战数据备份完整流程演示

发布时间:2026/7/17 15:08:34
鸿蒙应用开发实战【92】— 实战数据备份完整流程演示 鸿蒙应用开发实战【92】— 实战数据备份完整流程演示本文是「号码助手全栈开发系列」第 92 篇持续更新中…开源社区https://openharmonycrossplatform.csdn.net前言号码助手的数据备份功能是完整的 CRUD 文件 IO 综合实战。通过将数据库中的 cards 和 app_bindings 表序列化为 JSON 文件并支持从文件恢复数据展示了一个典型的「导出→持久化→恢复」功能链路。本篇涵盖备份数据结构设计、JSON 序列化与ohos.file.fs文件操作、备份列表管理、旧备份自动清理、数据恢复流程清空 → 插入 → id 映射。一、备份数据结构文件pages/BackupPage.ets第 25-31 行/** 备份文件内容结构 */interfaceBackupData{version:number// 备份格式版本便于后续升级exportTime:number// 导出时间戳appName:string// 应用名称cards:CardEntity[]// 全部卡号bindings:AppBindingEntity[]// 全部应用绑定}采用version 字段作为向前兼容策略。未来版本可以读取旧版备份文件做格式转换。二、备份完整流程2.1 备份按钮触发// BackupPage.ets 第 115 行privateasyncdoBackup():Promisevoid{if(this.backing)returnthis.backingtruetry{// 1. 读取全量数据constcardsawaitCardDao.listAll()constbindingsawaitAppBindingDao.listAll()// 2. 构造备份对象constbackup:BackupData{version:1,exportTime:Date.now(),appName:号码助手,cards,bindings}constjsonJSON.stringify(backup)// 3. 确保备份目录存在constdirthis.getBackupDir()// context.filesDir /backupstry{fs.accessSync(dir)}catch{fs.mkdirSync(dir)// 目录不存在则创建}// 4. 写入 JSON 文件constfileNamebackup_${Date.now()}.jsonconstfilePathdir/fileNameconstfilefs.openSync(filePath,fs.OpenMode.CREATE|fs.OpenMode.WRITE_ONLY|fs.OpenMode.TRUNC)fs.writeSync(file.fd,json)fs.closeSync(file.fd)// 5. 自动清理旧备份保留最新 5 个this.cleanOldBackups(dir)// 6. 刷新列表 提示this.loadBackupFiles()promptAction.showToast({message:备份成功${cards.length}张卡 ·${bindings.length}个应用})}catch(e){hilog.error(0x0000,TAG,备份失败: %{public}s,JSON.stringify(e))promptAction.showToast({message:备份失败请重试})}finally{this.backingfalse}}2.2 关键 API 说明API用途所属模块fs.accessSync(path)检查目录是否存在ohos.file.fsfs.mkdirSync(path)创建目录ohos.file.fsfs.openSync(path, mode)打开/创建文件ohos.file.fsfs.writeSync(fd, data)写入文件内容ohos.file.fsfs.closeSync(fd)关闭文件描述符ohos.file.fsfs.listFileSync(dir)列出目录所有文件ohos.file.fsfs.statSync(path)获取文件属性大小、时间ohos.file.fsfs.unlinkSync(path)删除文件ohos.file.fsfs.readText(path)异步读取文本文件ohos.file.fs2.3 自动清理策略/** 保留最新 5 个备份清理多余的旧文件 */privatecleanOldBackups(dir:string):void{try{constfilesfs.listFileSync(dir).filter((f:string)f.endsWith(.json)).sort()if(files.length5){files.slice(0,files.length-5).forEach((name:string){try{fs.unlinkSync(dir/name)}catch{/* ignore */}})}}catch{/* ignore */}}三、数据恢复完整流程3.1 恢复确认对话框// 第 183 行this.getUIContext().showAlertDialog({title:确认恢复,message:恢复${fileName}后当前所有数据将被替换此操作不可撤销。确定继续吗,buttons:[{value:取消,action:(){}},{value:确定恢复,action:(){this.executeRestore(fileName)}}]})3.2 核心恢复逻辑privateasyncexecuteRestore(fileName:string):Promisevoid{this.restoringtruetry{// 1. 读取备份文件constfilePaththis.getBackupDir()/fileNameconstcontentawaitfs.readText(filePath)constbackupJSON.parse(content)asBackupData// 2. 清空现有数据先删子表再删主表conststoreDatabaseService.getInstance().getStore()awaitstore.executeSql(DELETE FROM app_bindings)awaitstore.executeSql(DELETE FROM cards)// 重置自增 id 计数器awaitstore.executeSql(DELETE FROM sqlite_sequence WHERE namecards)awaitstore.executeSql(DELETE FROM sqlite_sequence WHERE nameapp_bindings)// 3. 还原卡号并建立 oldId → newId 映射constidMapnewMapnumber,number()for(constcardofbackup.cards){constnewCard:CardEntity{label:card.label,phone_number:card.phone_number,carrier:card.carrier,color:card.color,// ...其他字段}constnewIdawaitCardDao.create(newCard)idMap.set(card.id??0,newId)}// 4. 还原应用绑定card_id 更新为新 idfor(constbindingofbackup.bindings){constnewCardIdidMap.get(binding.card_id)??0if(newCardId0)continueawaitAppBindingDao.create({...binding,id:undefined,card_id:newCardId})}promptAction.showToast({message:恢复成功${backup.cards.length}张卡 ·${backup.bindings.length}个应用})}catch(e){hilog.error(0x0000,TAG,恢复失败: %{public}s,JSON.stringify(e))promptAction.showToast({message:恢复失败请检查备份文件是否完整})}finally{this.restoringfalse}}四、id 映射策略详解恢复时最大的挑战旧记录的card_id在新数据库中不再是同一个 id。备份文件 新数据库 ──────────────────────────────── Card(id5) ──→ Card(id1) ← AUTOINCREMENT 重新分配 ↑ AppBinding(card_id5) ──┘ 需要映射为 card_id1解决方案oldId(5) → 插入新记录得到 newId(1) → idMap.set(5, 1) oldId(5) → idMap.get(5) 1 → AppBinding.card_id 1五、备份文件管理功能代码说明涉及 API自动备份AppStorage存储开关开启时每次添加/修改自动备份AppStorage立即备份doBackup()手动触发全量备份fs.writeSync备份历史loadBackupFiles()按时间倒序展示fs.listFileSync单文件恢复executeRestore()清空 重建 映射fs.readText DAO删除备份deleteBackup()删除文件 刷新列表fs.unlinkSync自动清理cleanOldBackups()保留最新 5 个fs.listFileSync六、备份文件示例{version:1,exportTime:1720000000000,appName:号码助手,cards:[{id:1,label:工作号,phone_number:13800138000,carrier:中国移动,color:blue,sort_order:0,created_at:1719878400000,updated_at:1719878400000}],bindings:[{id:1,app_name:支付宝,card_id:1,status:使用中,source:手动,created_at:1719878400000,updated_at:1719878400000}]}小结阶段核心动作涉及 API导出数据CardDao.listAll AppBindingDao.listAllDAO 查询序列化JSON.stringify → 写入文件ohos.file.fs备份列表fs.listFileSync → 解析文件名时间戳fs.statSync数据恢复fs.readText → JSON.parse → 清空 → 插入fs.readText DAOid 映射MapoldId, newId迭代映射自动清理排序 → 保留最新 5 个fs.unlinkSync如果这篇文章对你有帮助欢迎点赞、收藏⭐、关注你的支持是我持续创作的动力相关资源开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.netHarmonyOS 文件管理 APIhttps://developer.huawei.com/consumer/cn/doc/harmonyos-guides/file-management-overviewHarmonyOS 官方文档https://developer.huawei.com/consumer/cn/doc/HarmonyOS hilog文档https://developer.huawei.com/consumer/cn/doc/harmonyos-references/hilogHarmonyOS testinghttps://developer.huawei.com/consumer/cn/doc/harmonyos-guides/unit-testHarmonyOS 安全与权限https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/permissions-overview

相关新闻