#HarmonyOS NEXT 体验官# 鸿蒙开发实战--Base64对文本编解码 原创
作者:吴来斌
前言:本篇文章使用ArkTS自带Base64进行处理,目前在最新的DevEco Studio里面使用预览器调试没有结果,最好用真机测试。
一、效果展示
1.1 中文编解码结果
1.2 英文编解码结果
二、Base64原理
Base64编码因其能够解决文本数据传输和存储中的兼容性问题、简化传输过程、增强可读性以及提供一定程度的数据完整性校验,而在多种场合下得到广泛应用。
Base64编码的原理是将二进制数据(通常是8位字节,即1个字节)编码为64个可打印字符之一,从而形成一个纯文本字符串。这个过程主要涉及将每三个8位字节(共24位)划分为四个6位的块,并在每个6位块前添加两个0(即高位补零),以形成四个8位的字节。然后,这些8位字节被映射到Base64编码表中的字符。以下是Base64编码原理的详细步骤:
2.1 编码过程
- 分组:
- 将原始数据每三个字节分为一组。如果最后不足三个字节,则根据需要进行填充(通常使用
=
字符)。
- 转换:
- 将每组的三个字节(共24位)视为一个长的二进制数。
- 将这个二进制数分为四个6位的部分。
- 在每个6位部分的前面添加两个0(高位补零),使其成为8位(即一个字节)。
- 映射:
- 使用Base64编码表,将这四个8位的字节映射为对应的Base64字符。Base64编码表包含64个字符,分别是A-Z、a-z、0-9、
+
和/
。
- 结果:
- 将映射得到的四个Base64字符依次排列,形成编码后的字符串。
- 如果原始数据长度不是3的倍数,则在编码后的字符串末尾添加一个或两个
=
字符作为填充。
2.2 编码表
Base64编码表包含以下64个字符:
A-Z, a-z, 0-9, +, /
这些字符分别对应64个不同的6位二进制数(在补零后形成的8位字节中,实际使用的只有低6位)。
2.3 示例
假设我们要对字符串"Man"进行Base64编码:
- ASCII值:
- "M"的ASCII值是77(二进制:01001101)
- "a"的ASCII值是97(二进制:01100001)
- "n"的ASCII值是110(二进制:01101110)
- 组合:
- 将这三个ASCII值的二进制表示连接起来:010011010110000101101110
- 分组:
- 分为四组6位二进制数:010011 010110 000101 101110
- 补零:
- 每组前补两个0:00010011 00010110 00000101 00101110
- 映射:
- 根据Base64编码表,这四组二进制数分别对应T、W、F、u。
- 结果:
- 因此,"Man"的Base64编码是"TWFu"。
2.4 注意事项
- Base64编码会增加数据的大小,因为每三个字节被编码为四个字符(增加约1/3)。
- 编码后的字符串仅包含可打印字符,便于在文本环境中传输和存储。
-
=
字符用作填充,以确保编码后的字符串长度是4的倍数。 - Base64编码是一种编码方式,不是加密方式,因此它不能提供数据的安全性保护。
三、项目创建
3.1 新建项目
打开DevEco后新建目录,项目名为Base64Coding
3.2 新建目录
在ets目录中新建目录,添加ConvertType.ets文件,里面包含Uint8Array和String互转操作接口。
3.3 主要目录
├─ets
│ ├─entryability
│ ├─entrybackupability
│ ├─pages
│ │ └─index.ets
│ └─utils
│ └─ConvertType.ets //文本类型转换
└─resources
└─......
四、源码
4.1 ConvertType.ets接口源码
/*
* 文件名: ConvertType.ets
* 作者: Rybin Wu
* 创建日期: 2024-08-05
* 描述: 这个文件提供Uint8Array和String互转操作的两个接口
*/
import { buffer } from '@kit.ArkTS';
// 字符串转成字节流
export function stringToUint8Array(str: string) {
return new Uint8Array(buffer.from(str, 'utf-8').buffer);
}
// 字节流转成可理解的字符串
export function uint8ArrayToString(array: Uint8Array) {
// 将UTF-8编码转换成Unicode编码
let out: string = '';
let index: number = 0;
let len: number = array.length;
while (index < len) {
let character = array[index++];
switch (character >> 4) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
out += String.fromCharCode(character);
break;
case 12:
case 13:
out += String.fromCharCode(((character & 0x1F) << 6) | (array[index++] & 0x3F));
break;
case 14:
out += String.fromCharCode(((character & 0x0F) << 12) | ((array[index++] & 0x3F) << 6) |
((array[index++] & 0x3F) << 0));
break;
default:
break;
}
}
return out;
}
4.2 index.ets接口源码
/*
* 文件名: Index.ets
* 作者: Rybin Wu
* 创建日期: 2024-08-05
* 描述: 主界面调用内置Base64接口和自定义类型互转接口
*/
import { util } from '@kit.ArkTS';
import { stringToUint8Array, uint8ArrayToString } from '../utils/ConvertType';
@Entry
@Component
struct Index {
@State text: string = '';
@State encode: string = '';
@State decode: string = '';
build() {
Column({ space: 10 }) {
Text('Base64编解码')
.fontSize(30)
.margin({ top: 20, bottom: 20 })
TextInput({ text: this.text, placeholder: '请输入文本...' })
.borderRadius(5)
.onChange((value) => {
this.text = value.trim()
})
Button('Base64编码')
.onClick(() => {
let base64 = new util.Base64Helper();
let u8Array = stringToUint8Array(this.text)
this.encode = base64.encodeToStringSync(u8Array, util.Type.BASIC)
})
Column() {
Text('Base64编码结果:')
.alignSelf(ItemAlign.Start)
Text(this.encode.length !== 0 ? this.encode : '')
.width('100%')
.height(100)
.borderWidth(1)
.borderRadius(5)
.borderStyle(BorderStyle.Dotted)
}
.width('100%')
Button('Base64解码')
.backgroundColor('#ff5fc61d')
.onClick(() => {
let base64 = new util.Base64Helper();
let u8Array = base64.decodeSync(this.encode, util.Type.BASIC)
this.decode = uint8ArrayToString(u8Array)
})
Column() {
Text('Base64解码结果:')
.alignSelf(ItemAlign.Start)
Text(this.decode.length !== 0 ? this.decode : '')
.width('100%')
.height(100)
.borderWidth(1)
.borderRadius(5)
.borderStyle(BorderStyle.Dotted)
}
.width('100%')
}
.width('100%')
.height('100%')
.padding({ left: 20, right: 20 })
}
}
五、问题处理
5.1 预览器操作警告
Warn:The Base64Helper.constructor interface in the Previewer is a mocked implementation and may behave differently than on a real device.
当日志中出现这样的警告时,虽然可以打印日志,但是操作没有结果。最好使用真机调试,因为模拟器目前还不支持中文输入。