数据备份与恢复:HarmonyOS APP数据保护
📌 核心要点:数据备份与恢复是应用数据安全的最后一道防线,HarmonyOS提供了本地备份、云端备份和分布式备份三种机制,确保数据万无一失
一、背景与动机
数据丢了,这事儿可大可小。轻则用户设置没了,重则几年积累的照片、聊天记录全没了。你肯定听过那种"手机坏了,数据全丢"的悲惨故事吧?
作为开发者,我们有责任帮用户守护好他们的数据。HarmonyOS在这方面做得挺全面——本地备份、云端备份、分布式备份,三重保障。而且备份恢复机制对应用透明,你只需要声明哪些数据需要备份,剩下的系统自动搞定。
说白了,备份恢复就是给数据买保险。平时感觉不到它的存在,但真出事儿的时候,你会发现这笔"保费"交得太值了。
二、核心原理
2.1 备份架构
HarmonyOS的备份恢复体系分三个层次:
2.2 备份类型对比
| 备份类型 | 存储位置 | 触发时机 | 适用场景 | 恢复速度 |
|---|---|---|---|---|
| 本地备份 | 设备存储 | 应用升级、定时 | 快速恢复、版本回退 | 极快 |
| 云端备份 | 华为云 | 定时、用户触发 | 跨设备恢复、灾难恢复 | 中等 |
| 分布式备份 | 对端设备 | 设备连接时 | 多设备协同 | 快 |
2.3 备份流程
完整的备份流程包含以下步骤:
- 数据收集:系统扫描需要备份的数据目录
- 数据打包:将数据序列化为备份文件
- 数据加密:可选的数据加密保护
- 数据传输:传输到备份目标位置
- 元数据记录:记录备份时间、版本等信息
- 清理旧备份:根据策略清理过期备份
2.4 恢复流程
恢复流程与备份相反:
- 备份定位:根据恢复请求找到对应备份
- 完整性校验:验证备份数据完整性
- 数据解密:如果备份加密则解密
- 数据解包:解析备份文件
- 数据写入:恢复到应用数据目录
- 应用通知:通知应用数据已恢复
三、代码实战
3.1 基础用法:配置备份规则
最简单的备份——在配置文件中声明需要备份的数据。
3.1.1 配置backup_config.json
{
"backupConfig": {
"version": "1.0",
"description": "应用数据备份配置",
// 需要备份的数据目录
"includeDirs": [
{
"path": "/data/storage/el2/base/files/",
"description": "用户文件数据",
"priority": "high"
},
{
"path": "/data/storage/el2/database/",
"description": "数据库文件",
"priority": "high"
},
{
"path": "/data/storage/el2/base/preferences/",
"description": "用户偏好设置",
"priority": "medium"
}
],
// 排除的文件或目录
"excludePatterns": [
"*.tmp",
"*.log",
"cache/*"
],
// 备份策略
"backupStrategy": {
"autoBackup": true, // 启用自动备份
"backupInterval": 86400000, // 备份间隔:24小时
"maxBackupCount": 5, // 最多保留5个备份
"enableCloudBackup": true, // 启用云端备份
"enableEncryption": true // 启用加密
},
// 恢复策略
"restoreStrategy": {
"conflictResolution": "latest", // 冲突解决:使用最新数据
"preserveUserData": true // 保留用户数据
}
}
}3.1.2 在module.json5中引用配置
{
"module": {
"abilities": [
{
"name": "MainAbility",
"metadata": [
{
"name": "ohos.backup.config",
"resource": "$profile:backup_config"
}
]
}
]
}
}3.2 进阶用法:自定义备份恢复逻辑
有些场景下,默认的备份机制不够灵活,需要自定义备份恢复逻辑。
import backupExtension from '@ohos.application.BackupExtension';
import fs from '@ohos.file.fs';
import relationalStore from '@ohos.data.relationalStore';
// 自定义备份Extension
export default class CustomBackupExtension extends backupExtension.BackupExtension {
// 备份数据
async onBackup(): Promise<void> {
console.info('[备份] 开始备份数据');
try {
// 1. 备份数据库数据
await this.backupDatabase();
// 2. 备份用户文件
await this.backupUserFiles();
// 3. 备份应用设置
await this.backupPreferences();
// 4. 生成备份清单
await this.generateBackupManifest();
console.info('[备份] 备份完成');
} catch (error) {
console.error(`[备份] 失败: ${JSON.stringify(error)}`);
throw error;
}
}
// 恢复数据
async onRestore(restoreType: backupExtension.RestoreType): Promise<void> {
console.info(`[恢复] 开始恢复数据,类型: ${restoreType}`);
try {
// 1. 验证备份完整性
const isValid = await this.verifyBackupIntegrity();
if (!isValid) {
throw new Error('备份数据损坏');
}
// 2. 恢复数据库数据
await this.restoreDatabase();
// 3. 恢复用户文件
await this.restoreUserFiles();
// 4. 恢复应用设置
await this.restorePreferences();
// 5. 数据迁移(如果版本不同)
await this.migrateDataIfNeeded();
console.info('[恢复] 恢复完成');
} catch (error) {
console.error(`[恢复] 失败: ${JSON.stringify(error)}`);
throw error;
}
}
// 备份数据库
private async backupDatabase(): Promise<void> {
const dbPath = '/data/storage/el2/database/MyApp.db';
const backupPath = '/data/storage/el2/base/files/backup/database_backup.db';
// 检查数据库是否存在
if (!fs.accessSync(dbPath)) {
console.info('[备份] 数据库不存在,跳过');
return;
}
// 复制数据库文件
fs.copyFileSync(dbPath, backupPath);
// 导出关键数据为JSON(可选)
const jsonData = await this.exportDatabaseToJson();
const jsonPath = '/data/storage/el2/base/files/backup/database_export.json';
const file = fs.openSync(jsonPath, fs.OpenMode.CREATE | fs.OpenMode.WRITE_ONLY);
fs.writeSync(file.fd, jsonData);
fs.closeSync(file);
console.info('[备份] 数据库备份完成');
}
// 导出数据库为JSON
private async exportDatabaseToJson(): Promise<string> {
try {
const config: relationalStore.StoreConfig = {
name: 'MyApp.db',
securityLevel: relationalStore.SecurityLevel.S1
};
const rdbStore = await relationalStore.getRdbStore(this.context, config);
// 导出关键表数据
const tables = ['users', 'notes', 'settings'];
const exportData: Record<string, any[]> = {};
for (const table of tables) {
const predicates = new relationalStore.RdbPredicates(table);
const resultSet = await rdbStore.query(predicates);
exportData[table] = [];
while (resultSet.goToNextRow()) {
const row: Record<string, any> = {};
for (let i = 0; i < resultSet.columnCount; i++) {
const columnName = resultSet.getColumnName(i);
row[columnName] = this.getColumnValue(resultSet, i);
}
exportData[table].push(row);
}
resultSet.close();
}
return JSON.stringify(exportData, null, 2);
} catch (error) {
console.error(`[导出] 失败: ${JSON.stringify(error)}`);
return '{}';
}
}
// 备份用户文件
private async backupUserFiles(): Promise<void> {
const userFilesDir = '/data/storage/el2/base/files/user_data';
const backupDir = '/data/storage/el2/base/files/backup/user_files';
// 创建备份目录
if (!fs.accessSync(backupDir)) {
fs.mkdirSync(backupDir, true);
}
// 递归复制文件
await this.copyDirectory(userFilesDir, backupDir);
console.info('[备份] 用户文件备份完成');
}
// 备份应用设置
private async backupPreferences(): Promise<void> {
const prefsPath = '/data/storage/el2/base/preferences/main_preferences.xml';
const backupPath = '/data/storage/el2/base/files/backup/preferences_backup.xml';
if (fs.accessSync(prefsPath)) {
fs.copyFileSync(prefsPath, backupPath);
console.info('[备份] 设置备份完成');
}
}
// 生成备份清单
private async generateBackupManifest(): Promise<void> {
const manifest = {
version: '1.0',
timestamp: Date.now(),
appVersion: this.getAppVersion(),
items: [
{ name: 'database', path: 'backup/database_backup.db', size: this.getFileSize('backup/database_backup.db') },
{ name: 'user_files', path: 'backup/user_files', type: 'directory' },
{ name: 'preferences', path: 'backup/preferences_backup.xml', size: this.getFileSize('backup/preferences_backup.xml') }
],
checksum: await this.calculateChecksum()
};
const manifestPath = '/data/storage/el2/base/files/backup/manifest.json';
const file = fs.openSync(manifestPath, fs.OpenMode.CREATE | fs.OpenMode.WRITE_ONLY);
fs.writeSync(file.fd, JSON.stringify(manifest, null, 2));
fs.closeSync(file);
console.info('[备份] 清单生成完成');
}
// 恢复数据库
private async restoreDatabase(): Promise<void> {
const backupPath = '/data/storage/el2/base/files/backup/database_backup.db';
const dbPath = '/data/storage/el2/database/MyApp.db';
if (!fs.accessSync(backupPath)) {
console.warn('[恢复] 数据库备份不存在,跳过');
return;
}
// 关闭现有数据库连接
await relationalStore.deleteRdbStore(this.context, 'MyApp.db');
// 恢复数据库文件
fs.copyFileSync(backupPath, dbPath);
console.info('[恢复] 数据库恢复完成');
}
// 恢复用户文件
private async restoreUserFiles(): Promise<void> {
const backupDir = '/data/storage/el2/base/files/backup/user_files';
const userFilesDir = '/data/storage/el2/base/files/user_data';
if (!fs.accessSync(backupDir)) {
console.warn('[恢复] 用户文件备份不存在,跳过');
return;
}
// 清空现有文件
if (fs.accessSync(userFilesDir)) {
fs.rmdirSync(userFilesDir, true);
}
// 恢复文件
await this.copyDirectory(backupDir, userFilesDir);
console.info('[恢复] 用户文件恢复完成');
}
// 恢复应用设置
private async restorePreferences(): Promise<void> {
const backupPath = '/data/storage/el2/base/files/backup/preferences_backup.xml';
const prefsPath = '/data/storage/el2/base/preferences/main_preferences.xml';
if (fs.accessSync(backupPath)) {
fs.copyFileSync(backupPath, prefsPath);
console.info('[恢复] 设置恢复完成');
}
}
// 验证备份完整性
private async verifyBackupIntegrity(): Promise<boolean> {
const manifestPath = '/data/storage/el2/base/files/backup/manifest.json';
if (!fs.accessSync(manifestPath)) {
console.error('[验证] 备份清单不存在');
return false;
}
try {
const file = fs.openSync(manifestPath, fs.OpenMode.READ_ONLY);
const stat = fs.statSync(manifestPath);
const buffer = new ArrayBuffer(stat.size);
fs.readSync(file.fd, buffer);
fs.closeSync(file);
const manifest = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(buffer) as any));
// 验证校验和
const currentChecksum = await this.calculateChecksum();
if (manifest.checksum !== currentChecksum) {
console.error('[验证] 校验和不匹配');
return false;
}
// 验证备份文件是否存在
for (const item of manifest.items) {
const itemPath = `/data/storage/el2/base/files/${item.path}`;
if (!fs.accessSync(itemPath)) {
console.error(`[验证] 备份项不存在: ${item.name}`);
return false;
}
}
return true;
} catch (error) {
console.error(`[验证] 失败: ${JSON.stringify(error)}`);
return false;
}
}
// 数据迁移(版本不同时)
private async migrateDataIfNeeded(): Promise<void> {
const manifestPath = '/data/storage/el2/base/files/backup/manifest.json';
const file = fs.openSync(manifestPath, fs.OpenMode.READ_ONLY);
const stat = fs.statSync(manifestPath);
const buffer = new ArrayBuffer(stat.size);
fs.readSync(file.fd, buffer);
fs.closeSync(file);
const manifest = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(buffer) as any));
const currentVersion = this.getAppVersion();
if (manifest.appVersion !== currentVersion) {
console.info(`[迁移] 版本不同,执行迁移: ${manifest.appVersion} -> ${currentVersion}`);
await this.executeMigration(manifest.appVersion, currentVersion);
}
}
// 执行数据迁移
private async executeMigration(fromVersion: string, toVersion: string): Promise<void> {
// 根据版本差异执行迁移逻辑
// 例如:表结构变更、数据格式转换等
console.info(`[迁移] 从 ${fromVersion} 迁移到 ${toVersion}`);
}
// 辅助方法
private async copyDirectory(src: string, dest: string): Promise<void> {
// 实现目录复制逻辑
if (!fs.accessSync(dest)) {
fs.mkdirSync(dest, true);
}
const files = fs.listFileSync(src);
for (const file of files) {
const srcPath = `${src}/${file}`;
const destPath = `${dest}/${file}`;
const stat = fs.statSync(srcPath);
if (stat.isDirectory()) {
await this.copyDirectory(srcPath, destPath);
} else {
fs.copyFileSync(srcPath, destPath);
}
}
}
private getColumnValue(resultSet: relationalStore.ResultSet, index: number): any {
const type = resultSet.getColumnType(index);
switch (type) {
case relationalStore.ColumnType.TYPE_INTEGER:
return resultSet.getLong(index);
case relationalStore.ColumnType.TYPE_FLOAT:
return resultSet.getDouble(index);
case relationalStore.ColumnType.TYPE_STRING:
return resultSet.getString(index);
case relationalStore.ColumnType.TYPE_BLOB:
return resultSet.getBlob(index);
case relationalStore.ColumnType.TYPE_NULL:
return null;
default:
return null;
}
}
private getAppVersion(): string {
// 从应用配置获取版本号
return '1.0.0';
}
private getFileSize(path: string): number {
const fullPath = `/data/storage/el2/base/files/${path}`;
if (fs.accessSync(fullPath)) {
const stat = fs.statSync(fullPath);
return stat.size;
}
return 0;
}
private async calculateChecksum(): Promise<string> {
// 计算备份文件的校验和
return 'checksum_' + Date.now();
}
}3.3 完整示例:带云端备份的完整方案
来个完整的实战案例——支持本地和云端备份的完整方案。
import backupExtension from '@ohos.application.BackupExtension';
import cloudBackup from '@ohos.cloud.backup';
import fs from '@ohos.file.fs';
import relationalStore from '@ohos.data.relationalStore';
// 完整的备份恢复Extension
export default class FullBackupExtension extends backupExtension.BackupExtension {
private cloudBackupClient: cloudBackup.CloudBackupClient | null = null;
async onCreate(): Promise<void> {
// 初始化云端备份客户端
this.cloudBackupClient = cloudBackup.createCloudBackupClient({
appId: 'com.example.myapp',
cloudPath: '/backup/myapp/'
});
console.info('[备份服务] 初始化完成');
}
// 执行备份
async onBackup(): Promise<void> {
console.info('[备份] 开始执行备份');
const backupId = `backup_${Date.now()}`;
const backupDir = `/data/storage/el2/base/files/backups/${backupId}`;
try {
// 创建备份目录
fs.mkdirSync(backupDir, true);
// 1. 本地备份
await this.performLocalBackup(backupDir);
// 2. 云端备份(异步)
this.performCloudBackup(backupDir, backupId).then(() => {
console.info('[云端备份] 完成');
}).catch((error) => {
console.error(`[云端备份] 失败: ${JSON.stringify(error)}`);
});
// 3. 清理旧备份
await this.cleanupOldBackups();
console.info(`[备份] 完成,ID: ${backupId}`);
} catch (error) {
console.error(`[备份] 失败: ${JSON.stringify(error)}`);
// 清理失败的备份
if (fs.accessSync(backupDir)) {
fs.rmdirSync(backupDir, true);
}
throw error;
}
}
// 本地备份
private async performLocalBackup(backupDir: string): Promise<void> {
// 备份数据库
await this.backupDatabase(backupDir);
// 备份文件
await this.backupFiles(backupDir);
// 备份设置
await this.backupSettings(backupDir);
// 生成备份元数据
await this.generateMetadata(backupDir);
}
// 备份数据库(增量备份)
private async backupDatabase(backupDir: string): Promise<void> {
const dbBackupPath = `${backupDir}/database`;
fs.mkdirSync(dbBackupPath, true);
// 获取数据库列表
const dbDir = '/data/storage/el2/database';
const dbFiles = fs.listFileSync(dbDir);
for (const dbFile of dbFiles) {
if (!dbFile.endsWith('.db')) continue;
const srcPath = `${dbDir}/${dbFile}`;
const destPath = `${dbBackupPath}/${dbFile}`;
// 检查是否需要增量备份
const lastBackupPath = await this.getLastBackupPath(dbFile);
if (lastBackupPath && await this.isIncrementalBackupNeeded(srcPath, lastBackupPath)) {
// 增量备份
await this.incrementalBackup(srcPath, lastBackupPath, destPath);
} else {
// 全量备份
fs.copyFileSync(srcPath, destPath);
}
console.info(`[数据库备份] ${dbFile} 完成`);
}
}
// 增量备份
private async incrementalBackup(srcPath: string, lastBackupPath: string, destPath: string): Promise<void> {
// 获取上次备份时间
const lastStat = fs.statSync(lastBackupPath);
const lastBackupTime = lastStat.mtime;
// 导出增量数据
const config: relationalStore.StoreConfig = {
name: srcPath.split('/').pop()!,
securityLevel: relationalStore.SecurityLevel.S1
};
const rdbStore = await relationalStore.getRdbStore(this.context, config);
// 查询修改时间大于上次备份时间的数据
const predicates = new relationalStore.RdbPredicates('data_table');
predicates.greaterThan('updated_time', lastBackupTime);
const resultSet = await rdbStore.query(predicates);
// 将增量数据写入备份文件
const incrementalData: any[] = [];
while (resultSet.goToNextRow()) {
const row: Record<string, any> = {};
for (let i = 0; i < resultSet.columnCount; i++) {
row[resultSet.getColumnName(i)] = this.getColumnValue(resultSet, i);
}
incrementalData.push(row);
}
resultSet.close();
// 写入增量备份文件
const file = fs.openSync(destPath, fs.OpenMode.CREATE | fs.OpenMode.WRITE_ONLY);
fs.writeSync(file.fd, JSON.stringify({
type: 'incremental',
baseBackup: lastBackupPath,
timestamp: Date.now(),
data: incrementalData
}));
fs.closeSync(file);
console.info(`[增量备份] ${incrementalData.length} 条记录`);
}
// 备份用户文件
private async backupFiles(backupDir: string): Promise<void> {
const filesBackupPath = `${backupDir}/files`;
fs.mkdirSync(filesBackupPath, true);
const userFilesDir = '/data/storage/el2/base/files/user_data';
if (!fs.accessSync(userFilesDir)) {
console.info('[文件备份] 用户文件目录不存在,跳过');
return;
}
// 压缩文件(节省空间)
await this.compressDirectory(userFilesDir, `${filesBackupPath}/user_data.zip`);
console.info('[文件备份] 完成');
}
// 备份设置
private async backupSettings(backupDir: string): Promise<void> {
const settingsBackupPath = `${backupDir}/settings`;
fs.mkdirSync(settingsBackupPath, true);
const prefsDir = '/data/storage/el2/base/preferences';
if (fs.accessSync(prefsDir)) {
const prefsFiles = fs.listFileSync(prefsDir);
for (const prefsFile of prefsFiles) {
const srcPath = `${prefsDir}/${prefsFile}`;
const destPath = `${settingsBackupPath}/${prefsFile}`;
fs.copyFileSync(srcPath, destPath);
}
}
console.info('[设置备份] 完成');
}
// 生成备份元数据
private async generateMetadata(backupDir: string): Promise<void> {
const metadata = {
version: '2.0',
timestamp: Date.now(),
appVersion: this.getAppVersion(),
device: this.getDeviceInfo(),
size: await this.calculateBackupSize(backupDir),
checksum: await this.calculateChecksum(backupDir),
components: {
database: fs.accessSync(`${backupDir}/database`),
files: fs.accessSync(`${backupDir}/files`),
settings: fs.accessSync(`${backupDir}/settings`)
}
};
const metadataPath = `${backupDir}/metadata.json`;
const file = fs.openSync(metadataPath, fs.OpenMode.CREATE | fs.OpenMode.WRITE_ONLY);
fs.writeSync(file.fd, JSON.stringify(metadata, null, 2));
fs.closeSync(file);
}
// 云端备份
private async performCloudBackup(backupDir: string, backupId: string): Promise<void> {
if (!this.cloudBackupClient) {
console.warn('[云端备份] 客户端未初始化');
return;
}
// 检查网络状态
const networkAvailable = await this.checkNetworkAvailable();
if (!networkAvailable) {
console.warn('[云端备份] 网络不可用,跳过');
return;
}
// 上传备份文件
const metadataPath = `${backupDir}/metadata.json`;
const metadata = JSON.parse(fs.readTextSync(metadataPath));
// 加密备份(可选)
const encryptedBackupPath = await this.encryptBackup(backupDir);
// 上传到云端
await this.cloudBackupClient.upload({
localPath: encryptedBackupPath || backupDir,
cloudPath: `/${backupId}/`,
metadata: metadata,
onProgress: (progress: number) => {
console.info(`[云端备份] 上传进度: ${progress}%`);
}
});
// 更新云端备份列表
await this.updateCloudBackupList(backupId, metadata);
}
// 执行恢复
async onRestore(restoreType: backupExtension.RestoreType): Promise<void> {
console.info(`[恢复] 开始恢复,类型: ${restoreType}`);
let backupPath: string;
switch (restoreType) {
case backupExtension.RestoreType.LOCAL:
backupPath = await this.selectLocalBackup();
break;
case backupExtension.RestoreType.CLOUD:
backupPath = await this.downloadCloudBackup();
break;
case backupExtension.RestoreType.DISTRIBUTED:
backupPath = await this.getDistributedBackup();
break;
default:
throw new Error(`不支持的恢复类型: ${restoreType}`);
}
if (!backupPath || !fs.accessSync(backupPath)) {
throw new Error('备份数据不存在');
}
// 验证备份
const isValid = await this.verifyBackup(backupPath);
if (!isValid) {
throw new Error('备份数据损坏');
}
// 执行恢复
await this.executeRestore(backupPath);
console.info('[恢复] 完成');
}
// 选择本地备份
private async selectLocalBackup(): Promise<string> {
const backupsDir = '/data/storage/el2/base/files/backups';
if (!fs.accessSync(backupsDir)) {
throw new Error('没有可用的本地备份');
}
// 获取所有备份
const backups = fs.listFileSync(backupsDir)
.filter(name => name.startsWith('backup_'))
.sort((a, b) => b.localeCompare(a)); // 按时间倒序
if (backups.length === 0) {
throw new Error('没有可用的本地备份');
}
// 返回最新的备份
return `${backupsDir}/${backups[0]}`;
}
// 下载云端备份
private async downloadCloudBackup(): Promise<string> {
if (!this.cloudBackupClient) {
throw new Error('云端备份客户端未初始化');
}
// 获取云端备份列表
const cloudBackups = await this.cloudBackupClient.listBackups();
if (cloudBackups.length === 0) {
throw new Error('没有可用的云端备份');
}
// 选择最新的备份
const latestBackup = cloudBackups.sort((a, b) => b.timestamp - a.timestamp)[0];
// 下载备份
const downloadPath = `/data/storage/el2/base/files/temp/cloud_backup_${Date.now()}`;
fs.mkdirSync(downloadPath, true);
await this.cloudBackupClient.download({
cloudPath: latestBackup.path,
localPath: downloadPath,
onProgress: (progress: number) => {
console.info(`[云端恢复] 下载进度: ${progress}%`);
}
});
// 解密备份(如果加密了)
const decryptedPath = await this.decryptBackup(downloadPath);
return decryptedPath || downloadPath;
}
// 执行恢复
private async executeRestore(backupPath: string): Promise<void> {
// 读取元数据
const metadataPath = `${backupPath}/metadata.json`;
const metadata = JSON.parse(fs.readTextSync(metadataPath));
// 恢复数据库
if (metadata.components.database) {
await this.restoreDatabase(`${backupPath}/database`);
}
// 恢复文件
if (metadata.components.files) {
await this.restoreFiles(`${backupPath}/files`);
}
// 恢复设置
if (metadata.components.settings) {
await this.restoreSettings(`${backupPath}/settings`);
}
// 数据迁移(如果版本不同)
if (metadata.appVersion !== this.getAppVersion()) {
await this.migrateData(metadata.appVersion, this.getAppVersion());
}
}
// 清理旧备份
private async cleanupOldBackups(): Promise<void> {
const backupsDir = '/data/storage/el2/base/files/backups';
const maxBackups = 5; // 最多保留5个备份
if (!fs.accessSync(backupsDir)) return;
const backups = fs.listFileSync(backupsDir)
.filter(name => name.startsWith('backup_'))
.sort((a, b) => b.localeCompare(a));
// 删除超出数量的旧备份
for (let i = maxBackups; i < backups.length; i++) {
const oldBackupPath = `${backupsDir}/${backups[i]}`;
fs.rmdirSync(oldBackupPath, true);
console.info(`[清理] 删除旧备份: ${backups[i]}`);
}
}
// 辅助方法(简化实现)
private async getLastBackupPath(dbFile: string): Promise<string | null> {
// 查找该数据库的上次备份路径
return null;
}
private async isIncrementalBackupNeeded(srcPath: string, lastBackupPath: string): Promise<boolean> {
// 判断是否需要增量备份
return false;
}
private async compressDirectory(src: string, dest: string): Promise<void> {
// 压缩目录(简化实现)
fs.copyFileSync(src, dest);
}
private async calculateBackupSize(backupDir: string): Promise<number> {
// 计算备份大小
return 0;
}
private async calculateChecksum(backupDir: string): Promise<string> {
return 'checksum_' + Date.now();
}
private getAppVersion(): string {
return '1.0.0';
}
private getDeviceInfo(): any {
return { model: 'unknown', os: 'HarmonyOS' };
}
private async checkNetworkAvailable(): Promise<boolean> {
return true;
}
private async encryptBackup(backupDir: string): Promise<string | null> {
return null;
}
private async decryptBackup(backupDir: string): Promise<string | null> {
return null;
}
private async updateCloudBackupList(backupId: string, metadata: any): Promise<void> {
// 更新云端备份列表
}
private async getDistributedBackup(): Promise<string> {
throw new Error('分布式备份暂不支持');
}
private async verifyBackup(backupPath: string): Promise<boolean> {
return true;
}
private async restoreDatabase(dbBackupPath: string): Promise<void> {
// 恢复数据库
}
private async restoreFiles(filesBackupPath: string): Promise<void> {
// 恢复文件
}
private async restoreSettings(settingsBackupPath: string): Promise<void> {
// 恢复设置
}
private async migrateData(fromVersion: string, toVersion: string): Promise<void> {
// 数据迁移
}
private getColumnValue(resultSet: relationalStore.ResultSet, index: number): any {
const type = resultSet.getColumnType(index);
switch (type) {
case relationalStore.ColumnType.TYPE_INTEGER:
return resultSet.getLong(index);
case relationalStore.ColumnType.TYPE_FLOAT:
return resultSet.getDouble(index);
case relationalStore.ColumnType.TYPE_STRING:
return resultSet.getString(index);
case relationalStore.ColumnType.TYPE_BLOB:
return resultSet.getBlob(index);
default:
return null;
}
}
onDestroy(): void {
console.info('[备份服务] 销毁');
}
}四、踩坑与注意事项
4.1 备份时机选择
坑点:在应用运行时备份,可能导致数据不一致。
解决方案:在应用暂停或退出时触发备份。
// 在Ability生命周期中触发备份
export default class MainAbility extends UIAbility {
onPause(): void {
// 应用暂停时触发备份
this.triggerBackup();
}
onDestroy(): void {
// 应用销毁时触发备份
this.triggerBackup();
}
private triggerBackup(): void {
// 发送备份请求
backupExtension.requestBackup('com.example.myapp');
}
}4.2 备份文件过大
坑点:备份文件过大,导致存储空间不足或上传超时。
解决方案:增量备份+压缩+分片上传。
// 备份策略配置
const backupStrategy = {
// 启用增量备份
enableIncremental: true,
// 压缩备份数据
enableCompression: true,
compressionLevel: 6, // 压缩级别:1-9
// 分片上传(大文件)
chunkSize: 5 * 1024 * 1024, // 每片5MB
// 排除大文件
excludeLargeFiles: true,
maxFileSize: 50 * 1024 * 1024 // 超过50MB的文件不备份
};4.3 恢复数据冲突
坑点:恢复数据时与现有数据冲突,导致数据覆盖或丢失。
解决方案:实现冲突解决策略。
// 冲突解决策略
enum ConflictResolution {
KEEP_LOCAL = 'keep_local', // 保留本地数据
KEEP_BACKUP = 'keep_backup', // 使用备份数据
MERGE = 'merge', // 合并数据
ASK_USER = 'ask_user' // 让用户选择
}
async function resolveConflict(localData: any, backupData: any, strategy: ConflictResolution): Promise<any> {
switch (strategy) {
case ConflictResolution.KEEP_LOCAL:
return localData;
case ConflictResolution.KEEP_BACKUP:
return backupData;
case ConflictResolution.MERGE:
// 合并策略:时间戳优先
if (localData.updatedTime > backupData.updatedTime) {
return localData;
} else {
return backupData;
}
case ConflictResolution.ASK_USER:
// 弹出对话框让用户选择
return await showConflictDialog(localData, backupData);
}
}4.4 云端备份失败
坑点:网络不稳定导致云端备份失败,但本地备份也被清理。
解决方案:先完成本地备份,再异步上传云端。
async function performBackup(): Promise<void> {
// 1. 本地备份(必须成功)
const localBackupPath = await performLocalBackup();
// 2. 云端备份(异步,失败不影响本地)
performCloudBackup(localBackupPath).catch(error => {
console.error(`[云端备份] 失败: ${JSON.stringify(error)}`);
// 标记待上传,下次重试
markPendingUpload(localBackupPath);
});
}4.5 备份加密安全
坑点:备份数据未加密,敏感信息泄露。
解决方案:启用备份加密。
// 加密备份配置
const encryptionConfig = {
enabled: true,
algorithm: 'AES-256-GCM',
keyDerivation: 'PBKDF2',
// 密钥来源
keySource: 'user_password', // 用户密码派生
// 加密范围
encryptDatabase: true,
encryptFiles: true,
encryptSettings: true
};五、HarmonyOS 6适配说明
HarmonyOS 6在备份恢复方面带来了重要增强:
5.1 新增特性
- 智能备份:系统根据数据变更频率自动调整备份策略
- 增量备份优化:增量备份效率提升50%+
- 云端备份加速:支持断点续传和并行上传
- 备份验证增强:支持数据完整性自动校验
5.2 API变更
新增API:
// 获取备份状态
const status = await backupExtension.getBackupStatus();
// 智能备份(系统自动判断备份时机)
await backupExtension.smartBackup();
// 增量备份查询
const changes = await backupExtension.getIncrementalChanges(sinceTime);
// 备份验证
const validationResult = await backupExtension.validateBackup(backupPath);废弃API:
forceBackup():改用smartBackup()
5.3 适配代码示例
import backupExtension from '@ohos.application.BackupExtension';
// HarmonyOS 6备份Extension
export default class HarmonyOS6BackupExtension extends backupExtension.BackupExtension {
async onBackup(): Promise<void> {
// 使用智能备份策略
const backupStrategy = await this.determineBackupStrategy();
console.info(`[智能备份] 策略: ${backupStrategy.type}`);
switch (backupStrategy.type) {
case 'full':
await this.performFullBackup();
break;
case 'incremental':
await this.performIncrementalBackup(backupStrategy.sinceTime);
break;
case 'delta':
await this.performDeltaBackup(backupStrategy.changes);
break;
}
}
// 确定备份策略
private async determineBackupStrategy(): Promise<BackupStrategy> {
// 获取上次备份时间
const lastBackupTime = await this.getLastBackupTime();
const timeSinceLastBackup = Date.now() - lastBackupTime;
// 获取数据变更统计
const changeStats = await backupExtension.getIncrementalChanges(lastBackupTime);
// 根据变更比例决定策略
const changeRatio = changeStats.changedRecords / changeStats.totalRecords;
if (timeSinceLastBackup > 7 * 24 * 60 * 60 * 1000) {
// 超过7天,全量备份
return { type: 'full' };
} else if (changeRatio > 0.3) {
// 变更超过30%,全量备份
return { type: 'full' };
} else if (changeRatio > 0.1) {
// 变更10%-30%,增量备份
return { type: 'incremental', sinceTime: lastBackupTime };
} else {
// 变更小于10%,差量备份
return { type: 'delta', changes: changeStats.changedRecords };
}
}
// 增量备份(HarmonyOS 6优化)
private async performIncrementalBackup(sinceTime: number): Promise<void> {
// 获取增量变更
const changes = await backupExtension.getIncrementalChanges(sinceTime);
// 按表分组
const changesByTable = this.groupChangesByTable(changes);
// 并行备份各表
const backupPromises = Object.entries(changesByTable).map(([table, records]) => {
return this.backupTableChanges(table, records);
});
await Promise.all(backupPromises);
console.info(`[增量备份] ${changes.changedRecords} 条记录`);
}
// 差量备份(HarmonyOS 6新增)
private async performDeltaBackup(changes: number): Promise<void> {
// 只备份变更的字段,而非整条记录
const deltaChanges = await this.getDeltaChanges();
const backupPath = this.getBackupPath();
const file = fs.openSync(backupPath, fs.OpenMode.CREATE | fs.OpenMode.WRITE_ONLY);
fs.writeSync(file.fd, JSON.stringify({
type: 'delta',
timestamp: Date.now(),
deltas: deltaChanges
}));
fs.closeSync(file);
console.info(`[差量备份] ${deltaChanges.length} 个字段变更`);
}
// 云端备份(HarmonyOS 6加速)
private async performCloudBackup(localBackupPath: string): Promise<void> {
const cloudClient = cloudBackup.createCloudBackupClient({
appId: 'com.example.myapp',
// HarmonyOS 6新增配置
enableResume: true, // 启用断点续传
parallelUpload: 3, // 并行上传数
compressBeforeUpload: true // 上传前压缩
});
// 上传(支持断点续传)
await cloudClient.upload({
localPath: localBackupPath,
cloudPath: `/backup/${Date.now()}/`,
onProgress: (progress: number, speed: number) => {
console.info(`[云端上传] 进度: ${progress}%, 速度: ${speed} KB/s`);
},
onResume: () => {
console.info('[云端上传] 恢复中断的上传');
}
});
}
// 备份验证(HarmonyOS 6增强)
async onRestore(restoreType: backupExtension.RestoreType): Promise<void> {
const backupPath = await this.getBackupPath(restoreType);
// 验证备份完整性
const validationResult = await backupExtension.validateBackup(backupPath);
if (!validationResult.isValid) {
// 尝试修复
const repairResult = await this.repairBackup(backupPath, validationResult.errors);
if (!repairResult.success) {
throw new Error('备份数据损坏且无法修复');
}
}
// 执行恢复
await this.executeRestore(backupPath);
}
// 辅助方法
private async getLastBackupTime(): Promise<number> {
return Date.now() - 24 * 60 * 60 * 1000;
}
private async performFullBackup(): Promise<void> {
// 全量备份实现
}
private groupChangesByTable(changes: any): Record<string, any[]> {
return {};
}
private async backupTableChanges(table: string, records: any[]): Promise<void> {
// 备份表变更
}
private async getDeltaChanges(): Promise<any[]> {
return [];
}
private getBackupPath(): string {
return '';
}
private async getBackupPath(restoreType: backupExtension.RestoreType): Promise<string> {
return '';
}
private async repairBackup(backupPath: string, errors: any[]): Promise<any> {
return { success: false };
}
private async executeRestore(backupPath: string): Promise<void> {
// 执行恢复
}
}
interface BackupStrategy {
type: 'full' | 'incremental' | 'delta';
sinceTime?: number;
changes?: number;
}5.4 性能优化建议
HarmonyOS 6环境下,充分利用智能备份:
// 性能优化配置
const performanceConfig = {
// 启用智能备份(推荐)
enableSmartBackup: true,
// 备份频率调整
autoAdjustFrequency: true,
minBackupInterval: 6 * 60 * 60 * 1000, // 最小6小时
maxBackupInterval: 48 * 60 * 60 * 1000, // 最大48小时
// 增量备份优化
incrementalThreshold: 0.3, // 变更超过30%触发全量备份
// 云端备份优化
cloudBackupConfig: {
parallelUpload: 3, // 3线程并行上传
chunkSize: 10 * 1024 * 1024, // 每片10MB
enableResume: true // 启用断点续传
}
};六、总结
| 维度 | 评价 |
|---|---|
| 学习难度 | ⭐⭐⭐ |
| 使用频率 | ⭐⭐⭐ |
| 重要程度 | ⭐⭐⭐⭐⭐ |
| 调试难度 | ⭐⭐⭐⭐ |
核心收获:
- 备份恢复是数据安全的最后一道防线,宁可备而不用,不可用而不备
- 三重备份机制各有优势:本地备份快、云端备份安全、分布式备份灵活
- 增量备份大幅减少备份开销,但要注意定期全量备份
- 冲突解决策略要提前设计,恢复时的数据冲突处理很关键
- HarmonyOS 6的智能备份是重大改进,系统自动优化备份策略,开发者更省心
下一步建议:
- 研究分布式场景下的跨设备备份恢复
- 探索端云协同的备份策略
- 实现用户可控的备份管理界面
- 学习数据迁移和版本兼容处理
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。