鸿蒙NEXT API使用指导之文件压缩和邮件创建
鸿蒙NEXT API 使用指导
- 一、前言
- 二、邮件创建
- 1、拉起垂类应用
- 2、 UIAbilityContext.startAbilityByType 原型
- 2.1、wantParam
- 2.2、abilityStartCallback 与 callback
- 3、拉起邮箱类应用
- 3.1、单纯拉起邮箱应用
- 3.2、传入带附件的邮件
- 三、压缩文件
- 1、认识 zlib
- 2、压缩处理
- 2.1、单文件压缩
- 2.2、多文件压缩
- 3、解压缩处理
- 4、获取文件信息
一、前言
上一篇,由于篇幅所限,并未对实现问题反馈功能所使用的两个核心系统 API,进行较为细致的使用说明,更为提及使用它们时应该注意的地方,为了避免初学者掉坑,本人特意撰写本篇文章进行补充。
二、邮件创建
邮件,对于普通人来说,或许是一个知道但用得不多的通讯工具,然而,在程序员群体,邮件确实使用频率相当高的,因为众多代码托管平台或开发者平台,都会基于邮箱进行账号注册,并且邮箱这种工具在联系相关开发者时,要比流行的即时通讯工具更为有效得多,毕竟很容易集成到开发者自己开发的相关系统平台中。
1、拉起垂类应用
言归正传,在鸿蒙 NEXT 应用开发框架中中,如果像拉起手机系统已安装的邮箱应用,并且传入一封内容填写好的邮件,是完全有现成 API 可以使用的,就是 UIAbilityContext.startAbilityByType和UIExtensionContentSession.startAbilityByType,想对来说,前者的使用更为简便,而在实现 TxtEdit 的问题反馈功能时,也是用了它,所以,本文重点了解前者,后者还请移步官方文档。
在 API13 版本中,UIAbilityContext.startAbilityByType 支持拉起的应用类型有如下:

因此,想要拉起邮箱类应用,只需将 type 参数设置为 mail 即可,具体来说就是形如下面的代码:
this.ctx.startAbilityByType("mail", wantParam, callback, (err) => { ... });
2、 UIAbilityContext.startAbilityByType 原型
UIAbilityContext.startAbilityByType 方法的声明原型如下:

有四个必传参数,并且第一个参数就是指定应用类型的参数。按照参数的声明顺序,下面我们了解一下剩余的三个参数的传值。
2.1、wantParam
在 UIAbilityContext.startAbilityByType 方法的第二个参数 wantParam,是一个 Record<string, Object> 类型,作用是设置拉起邮箱应用时需要一并传入的数据,针对 type=mail 时,这个 wantParam 可以传入的合法参数选项有如下:

都不是必填的,有两个需要注意的细节:
1) string 类型或 string[] 类型的数据值,都必须用encodeURI 编码一下;
2)邮箱地址,如收件人地址,在仅需填写一个邮箱地址的时候,如果错误地设置成 string 类型,即没有携带上中括号,那么就会出现能够成功拉起邮箱应用,但不会进入邮件编辑界面,也不会有任何错误抛出。
wantConstantFlags 的枚举值有如下几个:

这个 wantConstantFlags 选项,在需要创建带附件的邮件时,相当重要,设置错误将导致无法读取文件内容到邮件中。
2.2、abilityStartCallback 与 callback
abilityStartCallback 是一个 AbilityStartCallback 类型的参数,在 UIAbilityContext.startAbilityByType 中的作用,就是提供获取执行结果道德入口。
callback 则是一个 AsyncCallback<void>,为异步回调,用于获取接口调用是否成功。
这两个回调函数参数的区别,就在于 abilityStartCallback 是任务粒度的,而 callback 是接口粒度的,如此设计,是因为接口调用是否成功,与任务执行是否成功,是两码事,任务执行失败而接口调用不一定失败,但接口调用失败则任务执行一定失败。
3、拉起邮箱类应用
3.1、单纯拉起邮箱应用
如果不需要在拉起邮箱应用时,传入一封邮件,那么,wantParam 应该怎么传参呢?
思考一下,前面提到的针对邮箱类应用的 wantParam 选项,为什么都设置成非必填呢?如果传入一个空值的 wantParam 去拉取邮箱类应用,会有什么样的执行结果呢?想要知道会发生什么,不妨写段代码在真机上跑一下:
let callback: common.AbilityStartCallback = {onError: (code: number, name: string, message: string) => {Logger.error(`拉起邮箱失败,错误码:${code}, 错误名:${name}, 错误信息:${message}`, TAG)promptAction.showToast({message: "调用邮箱失败,请稍后重试",duration: 3000})},onResult: (result) => {Logger.info(`拉起邮箱成功,结果: ${JSON.stringify(result)}`, TAG)promptAction.showToast({message: '调用邮箱成功',duration: 3000})}
};
this.ctx.startAbilityByType("mail", {}, callback, (err) => {if (err) {Logger.error(`startAbilityByType调用失败,错误信息:${err.message}`, TAG)}Logger.info(`startAbilityByType调用成功`, TAG)
})
执行之后,首先会弹出应用选择面板,选择目标邮箱后,会进入目标邮箱应用并跳转到邮件新建界面。
这显然与我们想要的单纯进入邮箱应用主页,不进入邮件编辑页面,并不一致,为了达到这个目的,就应当从空传的 wantParam入手了;还记得前面介绍 wantParam 合法选项时,提到注意细节吗?其中就有一个强调邮箱地址要用 string[] 类型透传,但如果我们有意传成 string 类型,就如下面的代码这般:
const wantParam: Record<string, Object> = {'sceneType': 1,'email': '15014366986@163.com', // 收件人邮箱地址
};
this.ctx.startAbilityByType("mail", wantParam, callback, (err) => {if (err) {Logger.error(`startAbilityByType调用失败,错误信息:${err.message}`, TAG)}Logger.info(`startAbilityByType调用成功`, TAG)
})
就能实现我们的目的,不过,显而易见,这种实现方式需要慎重,因为后续的 API 迭代中,可能会对 wantParam 中的选项的类型进行强校验,校验不通过就抛错。
3.2、传入带附件的邮件
利用 wantParam,我们可以实现调用邮箱应用并进入编辑界面,并且提前填写好相关内容,无需用户自己手动输入信息,比如利用下面的 wantParam 传入带附件的邮件内容:
const wantParam: Record<string, Object> = {'sceneType': 1,'email': [encodeURI("wy1589461@163.com")], // 收件人邮箱地址,多值以逗号分隔,对数组内容使用encodeURI()方法进行url编码'subject': encodeURI('TxtEdit用户使用问题反馈'), // 邮件主题,对内容使用encodeURI()方法进行url编码'body': encodeURI(mailBody), // 邮件正文,对内容使用encodeURI()方法进行url编码'ability.params.stream': [encodeURI(uri)], // 附件uri,多值以逗号分隔,对数组内容使用encodeURI()方法进行url编码'ability.want.params.uriPermissionFlag': wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION
};
这里给出的案例,显然是主送一人、无抄送和密送的情况,如果需要抄送和密送,那么就需要为 cc 选项和 bcc 选项设置邮箱地址;邮件要携带的附件,以[encodeURI(文件URI)]的形式,为选项 ability.params.stream 设置值,并且为了保证有权限去读取目标文件中的内容,ability.want.params.uriPermissionFlag 必须设置成 wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION。
三、压缩文件
从 ability.params.stream 接受 string[] 类型的数据值来看,邮件附件是支持同时携带多份文件的,但有时候为了尽可能减小邮件的体积、降低对带宽的占用和提供传输效率,将多份需要邮件发送的文件压缩成一个压缩包进行发送,是常用的操作。
除了邮件,很多网络传输文件场景中,也比较推荐以压缩包的形式,去传输多份文件,同时,大文件的网络传输,用压缩包的形式进行传输,可以极大的提高成功率。
在移动端,处理压缩包的情况比较少见,但这并不意味着手机操作系统就没有相应的功能,实际上,安卓系统和鸿蒙系统都支持打开、解压缩一定格式的压缩包文件,而目前使用量最大的鸿蒙4.x版本的系统中,用手机管家清理加速的时候,是能够对不常用应用和文件进行压缩处理、从而降低对存储空间的占用。
1、认识 zlib
在鸿蒙NEXT 开发框架中,有一个 @ohos.zlib 模块,该模块下提供用于文件压缩与解压缩的相关API,并且开箱可用,主要支持 .zip 和 .gzip 两种压缩包文件格式。
所有 API 可以大致划分为压缩处理、解压缩处理和获取文件信息三大类。
2、压缩处理
遵循先有鸡后有蛋的原则,我们先看压缩处理相关的 API。
通过归纳官方文档,梳理出关于文件压缩处理的 API,主要有:
1)zlib.compressFile 与 zlib.compressFiles
2) Checksum.adler32 与 Checksum.adler32Combine、Checksum.crc32与Checksum.crc32Combine、Checksum.crc64
3)Zip.compress 与 Zip.compressBound,Zip.deflateInit 与 Zip.deflateInit2,Zip.deflate 等 Zip.deflateXXXX
4)Gzip.write
从使用难易的角度来说,第一组是最容易使用的,所以 ,本文重点介绍,后面的几组供学有余力的读者,前往官方文档仔细摸索。
2.1、单文件压缩
开始介绍前,给大家普及一个知识点,在计算机操作系统中,目录也是文件,一种格式比较特殊的文件。
单文件压缩,可以使用zlib.compressFile,这里传授大家一个经验,就是阅读API文档或者在代码提示中选择API时,一定要留意API名称的单复数,单数形式命名的API,往往只能一次处理一份数据,而复数形式命名的API 则可以一次处理多份数据,举一反三,大家在封装自己的工具类的时候,也应该遵循这种规则。
zlib.compressFile 一共如下四个参数:

1)inFile 是待压缩的文件或目录,不论是文件还是目录,对应的路径都必须是沙箱路径,并且如果是文件夹,那么该文件夹应为非空文件夹,否则会引发解压缩操作报错。
2)outFile 是保存压缩数据的压缩包文件路径,注意文件名取名为xxx.zip
3)options,压缩配置相关的选项:
a、level,压缩等级,合法枚举值如下:

b、memLevel,压缩过程中内存使用程度

c、strategy,压缩策略

2.2、多文件压缩
压缩多文件时,虽然可以选择将整个目录进行压缩,然而,有时候,需要压缩的目标文件,并不是所在目录下的所有文件,仅仅是其中的几个,针对这种应用场景,对多个指定文件或指定目录进行压缩的操作,就必须支持,而鸿蒙 NEXT 开发框架,通过 zlib.compressFiles 进行支持。

zlib.compressFiles 的方法参数,相对于前面的单文件压缩方法,少了一个回调函数参数,并且第一个参数更名为 inFiles、使用 Array<string> 类型
3、解压缩处理
zlib 模块中,针对解压缩处理,同样提供了多组 API,但本文为了内容的相关性,这一节只介绍 zlib.decompressFile 的使用。
就解压缩来说,并不存在单文件和多文件的区分,目前应用市场上的压缩包工具,解压缩操作也都仅支持一次处理一个压缩包文件。
zlib.compressFile 和 zlib.decompressFile,针对同步和异步场景,提供了不同实现,知其一便知其所有。

decompressFile 的参数结构,与 compressFile 几乎是一样的,而这也是众多三方 API 库共同具有的特征,所以,也是我们应当学会和掌握的编程细节。
4、获取文件信息
对于解压缩功能,往往在真正进行解压缩之前,会先读取压缩包的相关文件信息,比如获取原始文件的大小,然后决定是否要执行解压缩操作,从而避免将用户的存储空间撑爆。
有需求便有市场,所以,zlib 模块提供了大量的用户获取压缩包文件信息的相关 API,有兴趣的到官方文档上仔细了解,这里重点介绍 zlib.getOriginalSize。
zlib.getOriginalSize 方法原型如下:

参数结构比较简单,仅需传入压缩包所在的沙箱路径即可,而压缩包对应的原始文件的大小,会以异步回调的方式返回,简单的使用如下:
et compressedFile = '/data/storage/el2/base/temp/test.zip';try {zlib.getOriginalSize(compressedFile).then((data: number) => {console.info(`getOriginalSize success. getOriginalSize: ${data}`);}).catch((errData: BusinessError) => {console.error(`errData is errCode:${errData.code} message:${errData.message}`);})
} catch (errData) {let code = (errData as BusinessError).code;let message = (errData as BusinessError).message;console.error(`errData is errCode:${code} message:${message}`);
}
由于文件压缩与解压缩,在移动端应用场景中,并不多见,同时,为了避免本文篇幅过长,这里就不再给出文件压缩与解压缩的详细使用案例,请读者见谅。
相关文章:
鸿蒙NEXT API使用指导之文件压缩和邮件创建
鸿蒙NEXT API 使用指导 一、前言二、邮件创建1、拉起垂类应用2、 UIAbilityContext.startAbilityByType 原型2.1、wantParam2.2、abilityStartCallback 与 callback 3、拉起邮箱类应用3.1、单纯拉起邮箱应用3.2、传入带附件的邮件 三、压缩文件1、认识 zlib2、压缩处理2.1、单文…...
javaEE-10.CSS入门
目录 一.什么是CSS 编辑二.语法规则: 三.使用方式 1.行内样式: 2.内部样式: 3.外部样式: 空格规范 : 四.CSS选择器类型 1.标签选择器 2.类选择器 3.ID选择器 4.通配符选择器 5.复合选择器 五.常用的CSS样式 1.color:设置字体颜色 2.font-size:设置字体大小 3…...
Spring Boot牵手Redisson:分布式锁实战秘籍
一、引言 在当今的分布式系统架构中,随着业务规模的不断扩大和系统复杂度的日益增加,如何确保多个服务节点之间的数据一致性和操作的原子性成为了一个至关重要的问题。在单机环境下,我们可以轻松地使用线程锁或进程锁来控制对共享资源的访问,但在分布式系统中,由于各个服务…...
制药行业 BI 可视化数据分析方案
一、行业背景 随着医药行业数字化转型的深入,企业积累了海量的数据,包括销售数据、生产数据、研发数据、市场数据等。如何利用这些数据,挖掘其价值,为企业决策提供支持,成为医药企业面临的重大挑战。在当今竞争激烈的…...
[学习笔记] Kotlin Compose-Multiplatform
Compose-Multiplatform 原文:https://github.com/zimoyin/StudyNotes-master/blob/master/compose-multiplatform/compose.md Compose Multiplatform 是 JetBrains 为桌面平台(macOS,Linux,Windows)和Web编写Kotlin UI…...
ubutun系统常用配置
目录 1. 更新系统 2. 安装 vim 文本编辑器 3. 扩展文件系统 4. 设置静态IP地址(可选) 5. 安装图形驱动 6. 安装常用软件 7. 调整启动项 8. 清理系统 9. 配置SSH 10. 安装VNC服务器(可选) 11. 安装桌面环境(…...
PHP函数介绍—get_headers(): 获取URL的响应头信息
概述:在PHP开发中,我们经常需要获取网页或远程资源的响应头信息。PHP函数get_headers()能够方便地获取目标URL的响应头信息,并以数组形式返回。本文将介绍get_headers()函数的用法,以及提供一些相关的代码示例。 get_headers()函…...
web前端录制canvas视频和video的声音,并合并成一个文件进行下载
一、captureStream captureStream是一个Web API方法,用于捕获指定元素的媒体流。该方法通常用于从<video>、<audio>或<canvas>元素中捕获实时视频流或音频流,以便进行进一步的处理,如直播、录制或分析。 captureStr…...
Golang 并发机制-7:sync.Once实战应用指南
Go的并发模型是其突出的特性之一,但强大的功能也带来了巨大的责任。sync.Once是由Go的sync包提供的同步原语。它的目的是确保一段代码只执行一次,而不管有多少协程试图执行它。这听起来可能很简单,但它改变了并发环境中管理一次性操作的规则。…...
【AI实践】Cursor上手-跑通Hello World和时间管理功能
背景 学习目的:熟悉Cursor使用环境,跑通基本开发链路。 本人背景:安卓开发不熟悉,了解科技软硬件常识 实践 基础操作 1,下载安装安卓Android Studio 创建一个empty project 工程,名称为helloworld 2&am…...
深度学习 视频推荐
以下为你呈现一个基于深度学习实现视频推荐的简化代码示例。这里我们使用的是协同过滤思想结合神经网络的方式,借助 TensorFlow 和 Keras 库来构建模型。在这个示例中,假设已有用户对视频的评分数据,目标是预测用户对未评分视频的评分,进而为用户推荐可能感兴趣的视频。 1…...
缓存组件<keep-alive>
缓存组件<keep-alive> 1.组件作用 组件, 默认会缓存内部的所有组件实例,当组件需要缓存时首先考虑使用此组件。 2.使用场景 场景1:tab切换时,对应的组件保持原状态,使用keep-alive组件 使用:KeepAlive | Vu…...
SpringBoot单机模式的极限是什么?为什么会引入分布式?
Spring Boot 单机模式的极限 Spring Boot 单机模式的极限主要体现在以下几个方面: 硬件资源限制: CPU:单机性能受限于 CPU 核心数和主频,无法无限扩展。内存:内存容量有限,无法应对大规模数据处理或高并发…...
【多模态大模型】系列4:目标检测(ViLD、GLIP)
目录 1 ViLD2 GLIP 1 ViLD OPEN-VOCABULARY OBJECT DETECTION VIA VISION AND LANGUAGE KNOWLEDGE DISTILLATION 从标题就能看出来,作者是把CLIP模型当成一个Teacher,去蒸馏他自己的网络,从而能Zero Shot去做目标检测。 现在的目标检测数据…...
计算机网络结课设计:通过思科Cisco进行中小型校园网搭建
上学期计算机网络课程的结课设计是使用思科模拟器搭建一个中小型校园网,当时花了几天时间查阅相关博客总算是做出来了,在验收后一直没管,在寒假想起来了简单分享一下,希望可以给有需求的小伙伴一些帮助 目录 一、设计要求 二、…...
从零到一:基于Rook构建云原生Ceph存储的全面指南(下)
接上篇:《从零到一:基于Rook构建云原生Ceph存储的全面指南(上)》 链接: link 六.Rook部署云原生CephFS文件系统 6.1 部署cephfs storageclass cephfs文件系统与RBD服务类似,要想在kubernetes pod里使用cephfs&#…...
mysql的语句备份详解
使用mysqldump工具备份(适用于逻辑备份) mysqldump是 MySQL 自带的一个非常实用的逻辑备份工具,它可以将数据库中的数据和结构以 SQL 语句的形式导出到文件中。 1. 备份整个数据库 mysqldump -u [用户名] -p [数据库名] > [备份文件名].…...
AutoMQ 如何实现没有写性能劣化的极致冷读效率
前言 追赶读(Catch-up Read,冷读)是消息和流系统常见和重要的场景。 削峰填谷:对于消息来说,消息通常用作业务间的解耦和削峰填谷。削峰填谷要求消息队列能将上游发送的数据堆积住,让下游在容量范围内消费…...
【Rabbitmq篇】高级特性----TTL,死信队列,延迟队列
目录 一.TTL ???1.设置消息的TTL 2.设置队列的TTL 3.俩者区别? 二.死信队列 定义: 消息成为死信的原因: 1.消息被拒绝(basic.reject 或 basic.nack) 2.消息过期(TTL) 3.队列达到最大长度? …...
【Java】多线程和高并发编程(三):锁(中)深入ReentrantLock
文章目录 3、深入ReentrantLock3.1 ReentrantLock和synchronized的区别3.2 AQS概述3.3 加锁流程源码剖析3.3.1 加锁流程概述3.3.2 三种加锁源码分析3.3.2.1 lock方法3.3.2.2 tryLock方法3.3.2.3 lockInterruptibly方法 3.4 释放锁流程源码剖析3.4.1 释放锁流程概述3.4.2 释放锁…...
Unity 高度可扩展的技能与多 Buff 框架详解
一、框架设计 1.1 核心思想 组件化设计: 将技能和 Buff 抽象为可复用的组件,通过组合不同的组件实现复杂的效果。 数据驱动: 使用 ScriptableObject 或 JSON 等数据格式定义技能和 Buff 的属性,方便配置和修改。 事件驱动: 利用 Unity 的事件系统或自…...
电路笔记(元器件):AD 5263数字电位计(暂记)
AD5263 是四通道、15 V、256位数字电位计,可通过SPI/I2C配置具体电平值。 配置模式: W引脚作为电位器的抽头,可在A-B之间调整任意位置的电阻值。也可将W与A(或B)引脚短接,A-W间的电阻总是0欧姆,通过数字接口调整电位器…...
《大规模动画优化(一):GPU 顶点动画的生成》
GPU 顶点动画(Vertex Animation Texture, VAT) GPU 顶点动画(Vertex Animation Texture, VAT)烘焙的核心思想是: 在 CPU 端预先计算动画顶点数据,并存储到纹理(Texture2D)中…...
webpack【初体验】使用 webpack 打包一个程序
打包前 共 3 个文件 dist\index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Webpack 示例&…...
VMware安装CentOS 7(全网超详细图文保姆版教程)
文章目录 一、下载及安装 VMware1.1 VMware下载1.2 CentOS下载 二、搭建虚拟机环境2.1 创建新虚拟机2.2 选择自定义2.3 选择虚拟机硬件兼容性2.4 选择稍后安装操作系统2.5 选择Linux系统 版本选择 centos 7 64位2.6 设备你虚拟机的名字和保存位置(保存位置建议在编辑…...
mysql BUG 导致 show processlist 有大量的show slave stauts 处于init状态
一、详细报错信息: 1、执行show slave status\G 卡住 && stop slave也卡住 2、show processlist 发现 Waiting for commit lock NULL 锁 3、错误日志报错主备同步用户认证失败 二、报错原因(分析过程): 1、排查备库日志…...
机器学习在癌症分子亚型分类中的应用
学习笔记:机器学习在癌症分子亚型分类中的应用——Cancer Cell 研究解析 1. 文章基本信息 标题:Classification of non-TCGA cancer samples to TCGA molecular subtypes using machine learning发表期刊:Cancer Cell发表时间:20…...
从MySQL优化到脑力健康:技术人与效率的双重提升
文章目录 零:前言一:MySQL性能优化的核心知识点1. 索引优化的最佳实践实战案例: 2. 高并发事务的处理机制实战案例: 3. 查询性能调优实战案例: 4. 缓存与连接池的优化实战案例: 二:技术工作者的…...
Qt:项目文件解析
目录 QWidget基础项目文件解析 .pro文件解析 widget.h文件解析 widget.cpp文件解析 widget.ui文件解析 main.cpp文件解析 认识对象模型 窗口坐标系 QWidget基础项目文件解析 .pro文件解析 工程新建好之后,在工程目录列表中有⼀个后缀为 ".pro" …...
react使用if判断
1、第一种 function Dade(req:any){console.log(req)if(req.data.id 1){return <span>66666</span>}return <span style{{color:"red"}}>8888</span>}2、使用 {win.map((req,index) > ( <> <Dade data{req}/>{req.id 1 ?…...
