【HarmonyOS NEXT】鸿蒙arrayBuffer和Uint8Array互相转化
一、概念溯源:ArrayBuffer与Uint8Array的本质
在鸿蒙(HarmonyOS NEXT)应用开发中,二进制数据的处理是绕不开的基础能力。无论是网络通信、文件读写、图片处理还是加解密,都会与ArrayBuffer和Uint8Array打交道。
1.1 ArrayBuffer:原始的内存块
ArrayBuffer代表一块固定长度的原始二进制数据缓冲区。可以把它想象成一块未经开垦的内存区域,它只负责占有一块连续的内存空间,但不提供任何手段来直接读写其中的数据。
-
特点:固定长度,创建后无法直接增减大小;本身不可读写,必须通过“视图”来操作。
-
创建方式:
typescript
// 创建一个长度为8字节的ArrayBuffer const buffer: ArrayBuffer = new ArrayBuffer(8); console.log(buffer.byteLength); // 输出: 8
在鸿蒙系统中,ArrayBuffer内部包含一块Native内存,其JS对象壳被分配在虚拟机本地堆(LocalHeap)上。作为一种可转移对象,ArrayBuffer在线程间传递时无需拷贝,能有效减少内存占用、提升性能。
1.2 Uint8Array:操作内存的视图
Uint8Array是一种类型化数组(TypedArray),它充当ArrayBuffer的“视图”,将缓冲区的数据解析为8位无符号整数数组。
-
本质:它并不拥有自己的数据,而是引用底层的
ArrayBuffer。每个元素对应1个字节(8位),取值范围为0~255。 -
常见用途:处理文件数据、图像像素、网络协议包、证书二进制数据等。
typescript
// 从已有的ArrayBuffer创建Uint8Array视图 const buffer = new ArrayBuffer(8); const uint8Array = new Uint8Array(buffer); // 此时uint8Array引用了buffer,修改uint8Array[0]会直接影响buffer
理解两者的关系:ArrayBuffer是“内存条”,Uint8Array是“读懂内存条上字节的工具”。
二、核心转换:互转的两种场景
2.1 ArrayBuffer → Uint8Array
将ArrayBuffer转化为Uint8Array是获取数据视图的过程,可以通过构造方法直接实现:
typescript
/**
* ArrayBuffer转Uint8Array
* @param buffer 原始二进制缓冲区
* @returns 对应的Uint8Array视图
*/
function arrayBufferToUint8Array(buffer: ArrayBuffer): Uint8Array {
// 方法1:直接构造(共享内存)
return new Uint8Array(buffer);
// 方法2:若需独立副本(不共享内存),使用slice
// return new Uint8Array(buffer.slice(0));
}
注意事项:通过new Uint8Array(buffer)创建的视图与buffer共享同一块内存,修改视图中的数据会同步影响原ArrayBuffer。
2.2 Uint8Array → ArrayBuffer
Uint8Array内部维护着对底层ArrayBuffer的引用,通过.buffer属性即可获取:
typescript
/**
* Uint8Array转ArrayBuffer
* @param array Uint8Array实例
* @returns 对应的ArrayBuffer
*/
function uint8ArrayToArrayBuffer(array: Uint8Array): ArrayBuffer {
// 方法1:直接访问buffer属性(共享内存)
return array.buffer as ArrayBuffer;
// 方法2:若需独立副本(不共享内存),需手动复制
// const newBuffer = new ArrayBuffer(array.length);
// const view = new Uint8Array(newBuffer);
// view.set(array);
// return newBuffer;
}
注意事项:array.buffer返回的ArrayBuffer与原Uint8Array共享内存。如需独立副本,需手动创建新的ArrayBuffer并用set()复制数据。
2.3 工具类封装(可直接复用)
typescript
export class BinaryUtil {
/**
* ArrayBuffer转Uint8Array
*/
public static arrayBufferToUint8Array(buffer: ArrayBuffer): Uint8Array {
return new Uint8Array(buffer);
}
/**
* Uint8Array转ArrayBuffer
*/
public static uint8ArrayToArrayBuffer(array: Uint8Array): ArrayBuffer {
return array.buffer as ArrayBuffer;
}
/**
* 复制一份独立的Uint8Array(不共享内存)
*/
public static cloneUint8Array(src: Uint8Array): Uint8Array {
const buffer = new ArrayBuffer(src.length);
const dst = new Uint8Array(buffer);
dst.set(src);
return dst;
}
/**
* 复制一份独立的ArrayBuffer(不共享内存)
*/
public static cloneArrayBuffer(src: ArrayBuffer): ArrayBuffer {
const dst = new ArrayBuffer(src.byteLength);
const srcView = new Uint8Array(src);
const dstView = new Uint8Array(dst);
dstView.set(srcView);
return dst;
}
}
三、进阶实战:常见业务场景
3.1 字符串与二进制互转(文件读写、网络请求)
在鸿蒙中处理文本文件或网络数据时,常需在字符串和二进制之间转换。核心利用util模块的TextEncoder和TextDecoder:
typescript
import { util } from '@kit.ArkTS';
// 字符串 → ArrayBuffer(编码)
function stringToArrayBuffer(str: string): ArrayBuffer {
const encoder = new util.TextEncoder();
const uint8Array = encoder.encodeInto(str); // 返回Uint8Array
return uint8Array.buffer as ArrayBuffer;
}
// ArrayBuffer → 字符串(解码)
function arrayBufferToString(buffer: ArrayBuffer, encoding: string = 'utf-8'): string {
const decoder = util.TextDecoder.create(encoding, { ignoreBOM: true });
const uint8Array = new Uint8Array(buffer);
return decoder.decodeWithStream(uint8Array, { stream: false });
}
典型场景:读取GBK编码的网络数据时,先将响应数据作为ArrayBuffer获取,再通过TextDecoder指定'gbk'解码为可读字符串。
3.2 Base64与二进制互转(图片传输、存储)
鸿蒙@kit.ArkTS提供了Base64Helper,配合二进制互转实现Base64编解码:
typescript
import { util } from '@kit.ArkTS';
const base64Helper = new util.Base64Helper();
// ArrayBuffer → Base64
function arrayBufferToBase64(buffer: ArrayBuffer): string {
const uint8Array = new Uint8Array(buffer);
return base64Helper.encodeToStringSync(uint8Array);
}
// Base64 → ArrayBuffer
function base64ToArrayBuffer(base64Str: string): ArrayBuffer {
const uint8Array: Uint8Array = base64Helper.decodeSync(base64Str);
return uint8Array.buffer as ArrayBuffer;
}
3.3 图片Uri/文件转ArrayBuffer
从图片URI或文件路径读取二进制数据,可用于上传或图像处理:
typescript
import { fileIo as fs } from '@kit.CoreFileKit';
function uriToArrayBuffer(uri: string): ArrayBuffer {
const file = fs.openSync(uri, fs.OpenMode.READ_ONLY);
// 先获取文件大小,更精确
const stat = fs.statSync(file.fd);
const buffer = new ArrayBuffer(stat.size);
fs.readSync(file.fd, buffer);
fs.closeSync(file.fd);
return buffer;
}
3.4 PixelMap与ArrayBuffer互转(图像处理)
处理图像像素数据时,可在PixelMap与ArrayBuffer间转换:
typescript
import { image } from '@kit.ImageKit';
// PixelMap → ArrayBuffer
function pixelMapToArrayBuffer(pm: image.PixelMap): ArrayBuffer {
const buffer = new ArrayBuffer(pm.getPixelBytesNumber());
pm.readPixelsToBufferSync(buffer);
return buffer;
}
// ArrayBuffer → PixelMap(需结合ImageSource)
function arrayBufferToPixelMap(buffer: ArrayBuffer): image.PixelMap {
const imageSource = image.createImageSource(buffer);
return imageSource.createPixelMapSync({
desiredPixelFormat: image.PixelMapFormat.RGBA_8888
});
}
3.5 与Native层交互(ArkTS → C++)
在鸿蒙跨语言调用中,Native层收到的是Uint8Array类型参数,通过.buffer获取ArrayBuffer后可传递给C++层处理:
typescript
// ArkTS侧
function passToNative(data: Uint8Array): void {
const buffer = data.buffer; // 获取ArrayBuffer
// 调用Native接口,传递buffer
nativeModule.processData(buffer);
}
四、深度注意:内存共享与独立副本
这是最容易踩的坑——转换时内存是否共享。
| 转换方式 | 内存关系 | 修改是否互相影响 |
|---|---|---|
new Uint8Array(buffer) |
共享 | ✅ 是 |
uint8Array.buffer |
共享 | ✅ 是 |
buffer.slice(0) 再构造 |
独立 | ❌ 否 |
手动new ArrayBuffer + set() |
独立 | ❌ 否 |
何时需要独立副本:
-
序列化/反序列化传输时,不希望数据被意外篡改
-
跨线程传递时,原数据可能被回收或修改
-
需要对数据进行修改,但不想影响原始缓冲区
创建独立副本的标准写法:
typescript
// 从Uint8Array创建独立ArrayBuffer
function createIndependentBuffer(src: Uint8Array): ArrayBuffer {
const dst = new ArrayBuffer(src.length);
const dstView = new Uint8Array(dst);
dstView.set(src); // 复制数据
return dst;
}
五、总结速查表
| 需求 | 代码示例 |
|---|---|
| ArrayBuffer → Uint8Array(共享) | new Uint8Array(buffer) |
| Uint8Array → ArrayBuffer(共享) | uint8Array.buffer |
| ArrayBuffer → Uint8Array(独立) | new Uint8Array(buffer.slice(0)) |
| Uint8Array → ArrayBuffer(独立) | const b = new ArrayBuffer(a.length); new Uint8Array(b).set(a); |
| 字符串 → ArrayBuffer | new util.TextEncoder().encodeInto(str).buffer |
| ArrayBuffer → 字符串 | util.TextDecoder.create('utf-8').decodeWithStream(new Uint8Array(buffer)) |
| Base64 → ArrayBuffer | new util.Base64Helper().decodeSync(str).buffer |
| ArrayBuffer → Base64 | new util.Base64Helper().encodeToStringSync(new Uint8Array(buffer)) |
理解
ArrayBuffer和Uint8Array的关系是鸿蒙二进制编程的基石。简单转换用.buffer和new Uint8Array()即可,涉及数据独立性时需手动复制。结合util模块的编解码能力,可覆盖绝大多数日常开发场景。
更多推荐


所有评论(0)