从HarmonyOS升级到HarmonyOS NEXT-环信SDK数据迁移
2024年6月21日 HarmonyOS NEXT (后续称之为 NEXT) 正式发布,随着 NEXT 稳定版的逐渐临近,各个应用及SDK正在忙于适配 NEXT 系统,同样也面临着系统升级时如何对数据的迁移适配。本文通过使用环信 SDK 介绍如何从 HarmonyOS 系统升级到 NEXT 系统时,进行应用数据的迁移适配。
应用数据迁移步骤
官方文档
在进行数据迁移之前,我们需要先了解升级到NEXT系统,应用数据迁移需要进行哪些步骤。下图是整个迁移流程:
上图1-4步骤,均是由系统触发完成,开发者需要在第4步实现自定义的“BackupExtensionAbility”逻辑,实现自定义的数据恢复及转换逻辑。
1. HarmonyOS APK沙箱数据搬迁到中间目录
在升级的过程中,HarmonyOS系统会按照一定的规则,将应用的沙箱数据放置到四个数据目录中,然后这些数据会被整体压缩后搬迁到中间目录。
开发过程中,应用数据常用到的数据目录为:
/data/user/{userId}/{APK包名}/
/data/media/{userId}/Android/data/{APK包名}/
`/data/user/{userId}/{APK包名}/` 对应的路径为 HarmonyOS APK 应用的`data/data/{包名}`路径目录,而`/data/media/{userId}/Android/data/{APK包名}/`对应的是应用的`sdcard/Android/data/{包名}/`路径目录。应用进行数据迁移的话,主要是关注这两块的数据迁移。
2. 华为应用市场安装 NEXT 版本的应用
NEXT系统的“数据迁移框架”会从华为应用市场根据开发者账号下载对应的 NEXT 版本的应用。具体关联,请参考文档:HarmonyOS应用关联Android应用。
3. 数据导入
在NEXT 应用安装完成后,“数据迁移框架”将应用沙箱数据从中间目录搬迁到备份恢复目录。
APK应用沙箱目录与备份恢复目录映射关系见下表中所示:
APK应用沙箱目录 | 备份恢复目录 | 备份恢复目录获取方式 |
---|---|---|
/data/user_de/{userId}/{APK包名}/ | /data/storage/el1/base/.backup/restore/{APK包名}/de/ | this.context.area = contextConstant.AreaMode.EL1; let deSourcePath = this.context.backupDir + "restore/{APK包名}/de/" |
/data/user/{userId}/{APK包名}/ | /data/storage/el2/base/.backup/restore/{APK包名}/ce/ | this.context.area = contextConstant.AreaMode.EL2; let ceSourcePath = this.context.backupDir + "restore/{APK包名}/ce/" |
/data/media/{userId}/Android/ data/{APK包名}/ | /data/storage/el2/base/.backup/restore/{APK包名}/A/data/ | this.context.area = contextConstant.AreaMode.EL2; let dataSourcePath = this.context.backupDir + "restore/{APK包名}/A/data/" |
/data/media/{userId}/Android/ obb/{APK包名}/ | /data/storage/el2/base/.backup/restore/{APK包名}/A/obb/ | this.context.area = contextConstant.AreaMode.EL2; let obbSourcePath = this.context.backupDir + "restore/{APK包名}/A/obb/" |
4. 数据转换
-
在应用数据搬迁到备份恢复目录后,“数据迁移框架”向“备份恢复框架”发送应用数据恢复请求。
-
“备份恢复框架”拉起应用的“BackupExtensionAbility”独立进程,启动应用数据恢复。
-
在“BackupExtensionAbility”独立进程中,开发者通过重写“onRestore”添加自定义逻辑,将备份恢复目录中的数据处理后保存到 NEXT 应用的沙箱中,完成应用的数据恢复。
-
“备份恢复框架”在应用数据恢复完成后,会清空备份恢复目录。
5. 启动 NEXT 应用,应用读取应用沙箱数据。
下面通过介绍环信 SDK 的数据迁移,来介绍具体的迁移过程。
需要迁移数据分析
以下为环信 SDK需要迁移的数据:
序号 | 数据名称 | 路径或者文件 | 备注 |
1 | SDK 数据库文件夹 | data/data/{包名}/files/easemobDB/ | |
2 | SDK 数据库相关文件夹 | data/data/{包名}/files/easemobDBPW/ | |
3 | SDK 配置文件 | data/data/{包名}/files/em_ap_config.json data/data/{包名}/files/em_config.json data/data/{包名}/files/server.json | |
4 | SDK 附件 | sdcard/Android/data/{包名}/{AppKey}/ |
-
环信 SDK 已经适配了在 NEXT 应用使用 HarmonyOS APK 数据库的逻辑。1 和 2 部分数据迁移到 NEXT的指定文件夹即可。
-
第 3 部分的配置文件直接迁移到NEXT的指定文件夹即可。
-
SDK 的附件,有如下情况:
(1)消息中的本地路径存储的是 Uri 。
这部分是在公共媒体库中,进行系统的升级后,经咨询华为,目前还没有映射关系。目前的处理可以参照如下思路:
-
判断本地文件不存在后,调用 `ChatManager#downloadAttachment` 或者
ChatManager#downloadThumbnail
方法从服务器下载文件资源后,然后再展示。 -
如果服务器文件过期,需要展示默认图片。
(2)消息中的本地路径存储的是第 4 部分的文件路径,则需要对路径进行转换。举例如下:
迁移过来的数据库中存储的附件本地路径为:
/storage/emulated/0/Android/data/{包名}/{appKey}/files/{receiver id}/{sender id}/f6dc0580-6b68-11ef-bac3-2d7c12bc3033.jpg
需要转换为:
/data/storage/el2/base/{appKey}/files/{receiver id}/{sender id}/f6dc0580-6b68-11ef-bac3-2d7c12bc3033.jpg
-
建议此步骤在展示附件时进行判断,并更新对应的localPath。
-
如果转换后,文件仍不存在,则需要展示默认图片。
环境准备及工具要求
HarmonyOS NEXT Developer Beta1或之后版本的终端设备一部。
HarmonyOS 系统终端设备一部。
工具要求:
工具 | 版本 | 说明 |
---|---|---|
“迁移调试”工具 | 205.0.0.115及之后版本 | 模拟验证数据迁移 |
DevEco Studio | DevEco Studio NEXT Developer Beta2及之后版本 | 请参考:DevEco Studio使用指南 |
Compatible SDK | 5.0.0(12) | 请参考:版本说明 |
注意:
“迁移调试”工具需要向华为申请获取。
HarmonyOS NEXT Developer Beta1及之后版本,厂商合作伙伴可通过IssueReporter平台提交工单,向华为方技术支持人员申请“迁移调试”工具,模拟进行数据迁移验证。公共开发者请通过“华为开发者联盟官网”->“支持”,在线提单方式获取。
HarmonyOS NEXT Developer Beta1之前版本,开发者可以通过系统内置“迁移调试”工具,模拟进行数据迁移验证。
BackupExtensionAbility实现
官方文档:BackupExtensionAbility的实现
1. 在entry/src/main/ets/目录下,点击 New > Directory 创建backupExtension目录。
2. 点击entry/src/main/ets/backupExtension/目录,点击 New > File 创建BackupExtension.ets文件。
3. 基于迁移环信SDK实现的BackupExtensionAbility示例代码。
import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit';
import { contextConstant } from '@kit.AbilityKit';
import fs from '@ohos.file.fs';
import { JSON } from '@kit.ArkTS';const TAG = `BackupExtensionAbility`;/*** serviceExt进程入口*/
export default class BackupExtension extends BackupExtensionAbility {onBackup () {console.log(TAG,`onBackup ok`);}/*** 数据恢复处理接口。接口是同步接口,其内部所有的异步操作请进行同步等待。** @param bundleVersion 版本信息*/async onRestore (bundleVersion : BundleVersion): Promise<void> {console.log(TAG, `onRestore ok ${JSON.stringify(bundleVersion)}`);if (bundleVersion.name.startsWith("0.0.0.0")){this.context.area = contextConstant.AreaMode.EL2;// 设置要迁移APK包的包名, 需要替换为需要迁移的APK的,下面为示例let apkPackageName = "com.xxx.xxx";let ceSourcePath = this.context.backupDir + `restore/${apkPackageName}/ce/`;let dataSourcePath = this.context.backupDir + `restore/${apkPackageName}/A/data/`;// 其中<USERID>当前固定为100, 参考文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/app-sandbox-directory-V5#应用沙箱路径和真实物理路径的对应关系const userId = 100;// 定义要迁移的APK沙箱目录let targetSDKSourcePath = ceSourcePath + "data/user/" + userId + "/" + apkPackageName + "/";if (fs.accessSync(targetSDKSourcePath)) {// 设置要迁移的APK files文件夹下的数据库文件夹const sdkDbDir = "easemobDB/";// 设置要迁移的APK files文件夹下的数据库附属文件夹const sdkDbPwdDir = "easemobDBPW/";// 设置要迁移的APK files文件夹下的SDK配置文件(4.3.0版本后有em_ap_config.json文件,之前版本的请忽略)const sdkConfigs = ["em_ap_config.json", "em_config.json", "server.json"];// 迁移 APK 沙箱目录 files 文件夹下的文件及文件夹到目标文件夹const fileDestDir = this.context.getApplicationContext().filesDir + "/";console.log(TAG, "fileDestDir: "+fileDestDir);console.log(TAG, "start to move db folder");await this.moveDirToTargetDir(targetSDKSourcePath + "files/" +sdkDbDir, fileDestDir + sdkDbDir);console.log(TAG, "end to move db folder");console.log(TAG, "start to move db pw folder");await this.moveDirToTargetDir(targetSDKSourcePath + "files/" +sdkDbPwdDir, fileDestDir + sdkDbPwdDir);console.log(TAG, "end to move db pw folder");sdkConfigs.forEach(async file => {const filePath = targetSDKSourcePath + "files/" + file;console.log(TAG, filePath + " to " + (fileDestDir+file));await this.moveFileToTargetPath(filePath, fileDestDir + file);})}let targetSDKDataSourcePath = dataSourcePath + "data/media/" + userId + "/Android/data/" + apkPackageName + "/";if (fs.accessSync(targetSDKDataSourcePath)) {// 设置要迁移 SD 卡下的的AppKey文件夹const sdkAppKeySourceDir = "easemob#easeim/";// 迁移 AppKey 文件夹到目标文件夹console.log(TAG, "start to move appkey folder");// 获取升级到 HarmonyOS NEXT 后SDK的目标文件夹路径const sdkDestDir = this.getTargetDestDir() + "/";console.log(TAG, sdkDestDir);await this.moveDirToTargetDir(targetSDKDataSourcePath + sdkAppKeySourceDir, sdkDestDir + sdkAppKeySourceDir);console.log(TAG, "end to move appkey folder");}// 在此处实现终端设备从HarmonyOS 4.0升级到HarmonyOS NEXT后,应用数据的转换和迁移// 涉及异步操作请进行同步等待console.log(TAG, `HarmonyOS to HarmonyOS NEXT scenario`);} else {// 在此处实现从HarmonyOS NEXT设备迁移到HarmonyOS NEXT设备后,应用数据的处理。无特殊要求,可以空实现// 涉及异步操作请进行同步等待console.log(TAG, `Other scenario`);}}async moveFileToTargetPath(sourcePath: string, destPath: string) {try {// 若mode为0,移动位置存在同名文件时,强制移动覆盖。await fs.moveFile(sourcePath, destPath);} catch (e) {console.log(TAG, "moveFileToTargetPath: " + JSON.stringify(e));}}async moveDirToTargetDir(sourceDir: string, destDir: string) {if (fs.accessSync(sourceDir)) {if (!fs.accessSync(destDir)) {fs.mkdirSync(destDir, true);}}try {// mode为2,文件级别强制覆盖。目标文件夹下存在与源文件夹名冲突的文件夹,若冲突文件夹下存在同名文件,则强制覆盖冲突文件夹下所有同名文件,未冲突文件将继续保留。console.log(TAG, sourceDir + " to " + destDir);await fs.moveDir(sourceDir, destDir, 2);} catch (e) {console.log(TAG, "moveDirToTargetDir: " + JSON.stringify(e));}}getTargetDestDir(): string {const filesDir = this.context.getApplicationContext().filesDir;console.log(TAG, "getTargetDestDir: "+filesDir);let lastPosition = filesDir.lastIndexOf('/files');return lastPosition != -1 ? filesDir.substring(0, lastPosition) : filesDir;}
}
4. 元数据资源配置
需要在 backup_config.json 文件中设置迁移场景,其他的元数据配置在本场景下不需要配置,示例如下:
{"allowToBackupRestore": true,"extraInfo": {"supportScene": ["hmos2next"]}
}
5. 在 module.json5 中注册 BackupExtension
需要在 entry 内的module.json5里面进行注册,示例代码如下:
"extensionAbilities": [{"description": "DemoBackupExtension","icon": "$media:app_icon","name": "BackupExtensionAbility","srcEntry": "./ets/backupExtension/BackupExtension.ets", // 对应BackupExtension.ets在代码仓中的位置"type": "backup", // 类型需要选择backup"exported": false,"metadata": [ // 对应注册的元数据资源{"name": "ohos.extension.backup","resource": "$profile:backup_config"}]}
]
开发者自验证
官方文档:开发者自验证
应用沙箱数据准备
APK 应用文件路径(从Android Studio的Device Explorer中看)与华为要求的准备的 APK 应用沙箱目录的映射关系:
APK 应用文件路径 | APK 应用沙箱目录 |
data/data/{包名}/ | /data/user/{userId}/{APK包名}/ |
sdcard/Android/data/{包名}/ | /data/media/{userId}/Android/data/{APK包名}/ |
应用沙箱数据准备参考官方文档即可,以下是需要注意的事项:
1. 准备好的应用沙箱文件需要整体放入到压缩包的目录下,例如:
/data/user/{userId}/{APK包名}/
放入到 {APK包名}/ce
后,目录路径为:{APK包名}/ce/data/user/{userId}/{APK包名}/
2. 准备好的压缩包,可以通过 DevEco Studio -> Device File Browser
找到目标设备,找到手机的 Download 文件夹路径(/storage/media/100/local/files/Docs/Download/
),右击 Download 文件夹,选择 “Upload…” 选中压缩好的压缩包。
3. 或者通过 hdc 命令,通过命令 hdc file send localPath/xxx.zip /storage/media/100/local/files/Docs/Download/xxx.zip
将文件从本地发送到手机。
NEXT 设备上模拟验证应用数据迁移
申请“迁移调试”工具
HarmonyOS NEXT Developer Beta1及之后版本,厂商合作伙伴可通过IssueReporter平台提交工单,向华为方技术支持人员申请“迁移调试”工具,模拟进行数据迁移验证。公共开发者请通过“华为开发者联盟官网”->“支持”,在线提单方式获取。
如果采取在线提单方式获取,可参考如下申请:
选择 `HarmonyOS NEXT -> HarmonyOS NEXT其他` 路径,申请格式为:
邮箱:
应用名称:
申请原因:
一般提单后,一天左右即可得到“迁移调试”工具的hap下载链接。
测试`BackupExtensionAbility`逻辑
按照官方文档进行调试时,点击启用迁移
按钮后,“迁移调试”工具会调起 NEXT 应用的`BackupExtensionAbility`独立进程,在这里会处理自定义的数据恢复操作。可以通过 DevEco Studio 的Log,选择backup进程({应用包名}:backup)查看迁移日志。可以在这一数据是否迁移成功。
其他
- 在数据迁移这一步,建议使用
mv
命令,文件的迁移效率要高于copy
命令。 - HarmonyOS应用关联Android应用。
端到端验证
在完成自验证步骤后,应用需要上架到华为应用市场,开发者需要模拟终端用户将终端设备从HarmonyOS升级到HarmonyOS NEXT的场景,端到端验证应用数据迁移结果。
具体步骤参考官方文档。
总结
经过“应用分析 -> 应用适配(含适配)-> 应用上架 -> 端到端验证”几个步骤最终完成应用数据的迁移,本文主要介绍的是 应用分析
和应用适配(含验证)
部分的介绍。希望本文可以帮助到正在和即将进行数据迁移的同学们。如果有需要探讨的地方可以在下方留言。
相关文章:

从HarmonyOS升级到HarmonyOS NEXT-环信SDK数据迁移
2024年6月21日 HarmonyOS NEXT (后续称之为 NEXT) 正式发布,随着 NEXT 稳定版的逐渐临近,各个应用及SDK正在忙于适配 NEXT 系统,同样也面临着系统升级时如何对数据的迁移适配。本文通过使用环信 SDK 介绍如何从 Harmon…...

Spring Boot-Bean注入问题
在Spring Boot开发中,Bean的注入是核心概念之一,它确保了组件之间的依赖关系得以维护并方便管理。然而,在实际开发过程中,Bean的注入有时会出现问题 1. Spring Boot中的Bean注入 首先,了解Spring Boot中的Bean注入机…...

【在Linux世界中追寻伟大的One Piece】IP分片和组装的具体过程
目录 1 -> IP分片和组装的具体过程 2 -> 分片与组装的过程 2.1 -> 分片 2.2 -> 组装 3 -> 分片与组装的示意图 3.1 -> 分片组装场景 1 -> IP分片和组装的具体过程 16位标识(id):唯一的标识主机发送的报文。如果IP报文在数据链路层被分片…...

2024年中国研究生数学建模竞赛A/C/D/E题全析全解
问题一: 针对问题一,可以采用以下低复杂度模型,来计算风机主轴及塔架的疲劳损伤累积程度。 建模思路: 累积疲劳损伤计算: 根据Palmgren-Miner线性累积损伤理论,元件的疲劳损伤可以累积。因此,…...

【图虫创意-注册安全分析报告-无验证方式导致安全隐患】
前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 1. 暴力破解密码,造成用户信息泄露 2. 短信盗刷的安全问题,影响业务及导致用户投诉 3. 带来经济损失,尤其是后付费客户,风险巨大,造…...

解决 npm ERR! node-sass 和 gyp ERR! node-gyp 报错问题
前言 在对一个项目进行npm i的时候 一直报错 npm ERR! code 1 npm ERR! path D:....\node-sass npm ERR! command failed 显示没有办法安装这个node-sass包 包兼容性 我电脑中默认使用的16的node版本,查找本地项目中这个包的版本和官方对于这个包的兼容ÿ…...

Golang | Leetcode Golang题解之第421题数组中两个数的最大异或值
题目: 题解: const highBit 30type trie struct {left, right *trie }func (t *trie) add(num int) {cur : tfor i : highBit; i > 0; i-- {bit : num >> i & 1if bit 0 {if cur.left nil {cur.left &trie{}}cur cur.left} else …...

每天一道面试题(15):谈谈你对CAS的理解
CAS(Compare And Swap)机制在并发编程中是一个非常重要的概念,主要用于实现原子性操作,避免使用传统的锁机制,从而提高性能。 CAS 的基本原理 CAS 的核心思想是通过比较当前值与预期值来决定是否执行修改。其流程如下…...

如何将MySQL卸载干净(win11)
相信点进来的你肯定是遇到了这个问题,那就是在安装MySQL的时候操作错误,最后结果不是自己想要的。卸载重新安装又发现安装不了。其实最主要的原因就是没有将MySQL卸载干净,那么如何把MySQL卸载干净?下面本篇文章就来给大家一步步介…...

【Linux】简易日志系统
目录 一、概念 二、可变参数 三、日志系统 一、概念 一个正在运行的程序或系统就像一个哑巴,一旦开始运行我们很难知晓其内部的运行状态。 但有时在程序运行过程中,我们想知道其内部不同时刻的运行结果如何,这时一个日志系统可以有效的帮…...

yum 集中式安装 LNMP
目录 安装 nginx 安装 mysql 安装 php 配置lnmp 配置 nginx 支持 PHP 解析 安装 nginx 修改yum源 将原本的yum源备份 vim /etc/yum.repos.d/nginx.repo [nginx-stable] namenginx stable repo baseurlhttp://nginx.org/packages/centos/7/$basearch/ gpgcheck0 enable…...

淘宝扭蛋机小程序,扭蛋机文化下的新体验
在数字化时代中,扭蛋机逐渐从传统的线下机器转移到了线上互联网中,市场得到了创新发展。扭蛋机小程序具有便捷、多样化、个性化的特点,迎合了当下消费者的线上消费习惯,又能够让扭蛋机玩家体验到新鲜有趣的扭蛋。 扭蛋机是一种热…...

Go搭建TcpSocket服务器
1.net包的强大功能 不可否认,go在网络服务开发有强大的优势。net库是一个功能强大的网络编程库,它提供了构建TCP、UDP和HTTP服务器和客户端所需的所有基础工具。 例如,搭建tcp服务器,只需要几行代码。 func main() {listener, …...

hadoop3跑第一个例子wordcount
1、创建目录 hdfs dfs -mkdir -p /user/input2、创建测试文件,并上传文件到hdfs echo 1 > 1.txt hdfs dfs -put 1.txt /user/input3、进入hadoop-3目录,并创建测试文件 cd /app/hadoop-3创建目录 mkdir wcinput cd wcinput 保存wc.input nano wc.i…...

Maven笔记(二):进阶使用
Maven笔记(二)-进阶使用 一、Maven分模块开发 分模块开发对项目的扩展性强,同时方便其他项目引入相同的功能。 将原始模块按照功能拆分成若干个子模块,方便模块间的相互调用,接口共享(类似Jar包一样之间引用、复用)…...

Apache ZooKeeper 及 Curator 使用总结
1. 下载 官网地址:Apache ZooKeeper 点击下载按钮 选择对应的版本进行下载 2. 使用 1、解压 tar -zxf apache-zookeeper-3.9.2-bin.tar.gz2、复制配置文件,有一个示例配置文件 conf/zoo_sample.cfg,此文件不能生效,需要名称为…...

深入探索:MATLAB中的硬件支持包(HSP)及其应用
在MATLAB环境中,硬件支持包(HSP)扮演着至关重要的角色,尤其是在与硬件交互和嵌入式系统开发方面。HSP提供了一套工具和库,使得MATLAB能够与特定的硬件平台进行有效通信,实现代码的生成和优化。本文将详细介…...

5.内容创作的未来:ChatGPT如何辅助写作(5/10)
引言 在信息爆炸的时代,内容创作已成为连接品牌与受众、传递信息与知识、以及塑造文化与观念的重要手段。随着数字媒体的兴起,内容创作的需求日益增长,对创作者的写作速度和质量提出了更高的要求。人工智能(AI)技术的…...

Day26_0.1基础学习MATLAB学习小技巧总结(26)——数据插值
利用空闲时间把碎片化的MATLAB知识重新系统的学习一遍,为了在这个过程中加深印象,也为了能够有所足迹,我会把自己的学习总结发在专栏中,以便学习交流。 参考书目: 1、《MATLAB基础教程 (第三版) (薛山)》 2、《MATL…...

SQL进阶技巧:火车票相邻座位预定一起可能情况查询算法 ?
目录 0 场景描述 1 数据准备 2 问题分析 2.1 分析函数法 2.2 自关联求解 3 小结...

神经网络构建原理(以MINIST为例)
神经网络构建原理(以MINIST为例) 在 MNIST 手写数字识别任务中,构建神经网络并训练模型来进行分类是经典的深度学习应用。MNIST 数据集包含 28x28 像素的手写数字图像(0-9),任务是构建一个神经网络,能够根据输入的图像…...

【ArcGIS微课1000例】0123:数据库中要素类批量转为shapefile
除了ArcGIS之外的其他GIS平台,想要打开ArcGIS数据库,可能无法直接打开,为了便于使用shp,建议直接将数据库中要素类批量转为shapefile。 文章目录 一、连接至数据库二、要素批量转shp一、连接至数据库 打开ArcMap,或者打开ArcCatalog,找到数据库连接,如下图: 数据库为个…...

【Elasticsearch系列十九】评分机制详解
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

神经网络通俗理解学习笔记(3)注意力神经网络
Tansformer 什么是注意力机制注意力的计算键值对注意力和多头注意力自注意力机制注意力池化及代码实现Transformer模型Transformer代码实现BERT 模型GPT 系列模型GPT-1模型思想GPT-2模型思想GPT-3 模型思想 T5模型ViT模型Swin Transformer模型GPT模型代码实现 什么是注意力机制…...

【C#】 EventWaitHandle的用法
EventWaitHandle 是 C# 中用于线程间同步的一个类,它提供了对共享资源的访问控制,以及线程间的同步机制。EventWaitHandle 类位于 System.Threading 命名空间下,主要用于实现互斥访问、信号量控制等场景。 创建 EventWaitHandle 创建一个 E…...

设计模式之结构型模式例题
答案:A 知识点 创建型 结构型 行为型模式 工厂方法模式 抽象工厂模式 原型模式 单例模式 构建器模式 适配器模式 桥接模式 组合模式 装饰模式 外观模式 享元模式 代理模式 模板方法模式 职责链模式 命令模式 迭代器模式 中介者模式 解释器模式 备忘录模式 观…...

camtasia2024绿色免费安装包win+mac下载含2024最新激活密钥
Hey, hey, hey!亲爱的各位小伙伴,今天我要给大家带来的是Camtasia2024中文版本,这款软件简直是视频制作爱好者的福音啊! camtasia2024绿色免费安装包winmac下载,点击链接即可保存。 先说说这个版本新加的功能吧&#…...

如何导入一个Vue并成功运行
注意1:要确保自己已经成功创建了一个Vue项目,创建项目教程在如何创建Vue项目 注意2:以下操作均在VS Code,教程在VS Code安装教程 一、Vue项目导入VS Code 1.点击文件,然后点击将文件添加到工作区 2. 选择自己的vue项…...

封装svg图片
前言 项目中有大量svg图片,为了方便引入,所以对svg进行了处理 一、svg是什么? svg是可缩放矢量图形,是一种图片格式 二、使用步骤 1.创建icons文件夹 将icons文件夹放进src中,并创建一个svg文件夹和index.js&…...

tomcat的Catalinalog和localhostlog乱码
找到tomcat安装目录的loging文件 乱码这两个由UTF-8改为GBK...