使用Node-API接口进行ArrayBuffer相关开发
=============================

#### 简介

ArrayBuffer是ArkTS中的一种数据类型，用于表示通用的、固定长度的原始二进制数据缓冲区。它提供了一种在ArkTS中有效地表示和操作原始二进制数据的方式。

#### 基本概念

*   **ArrayBuffer**：ArrayBuffer对象用来表示一个通用的、固定长度的原始二进制数据缓冲区。不能直接操作ArrayBuffer的内容，而是需要包装成TypedArray对象或DataView对象来读写。ArrayBuffer常用于处理大量的二进制数据，如文件、网络数据包等。

#### 场景和功能介绍

以下Node-API接口用于操作ArrayBuffer类型的数据。

| 接口 | 描述 |
| :-- | :-- |
| napi\_is\_arraybuffer | 检查一个值是否为ArrayBuffer，以确保正在处理正确的数据类型。需要注意的是，此函数只能判断一个值是否为ArrayBuffer，而不能判断一个值是否为TypedArray。要判断一个值是否为TypedArray，可以使用napi\_is\_typedarray函数。 |
| napi\_get\_arraybuffer\_info | 获取给定的ArrayBuffer对象的相关信息，包括数据指针和数据长度。 |
| napi\_detach\_arraybuffer | 将ArrayBuffer底层缓冲区与ArrayBuffer对象分离。分离后可以直接在C/C++中操作数据，而无需通过Node-API接口进行数据访问。 |
| napi\_is\_detached\_arraybuffer | 判断给定的ArrayBuffer是否已经被分离。 |
| napi\_create\_arraybuffer | 用于在Node-API模块中创建一个具有指定字节长度的ArkTS ArrayBuffer对象。 |

#### 使用示例

Node-API接口开发流程参考[使用Node-API实现跨语言交互开发流程](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/use-napi-process)，本文仅对接口对应C++及ArkTS相关代码进行展示。

本文cpp部分代码所需引用的头文件如下：

#include "napi/native\_api.h"
#include <cstring>
#include "hilog/log.h"

本文ArkTS侧示例代码所需的模块导入如下：

import { hilog } from '@kit.PerformanceAnalysisKit';
import testNapi from 'libentry.so';

#### \[h2\]napi\_is\_arraybuffer

判断给定ArkTS value是否为ArrayBuffer。

cpp部分代码

// napi\_is\_arraybuffer
static napi\_value IsArrayBuffer(napi\_env env, napi\_callback\_info info)
{
    // 接受一个入参
    size\_t argc = 1;
    napi\_value args\[1\] = {nullptr};
    napi\_get\_cb\_info(env, info, &argc, args, nullptr, nullptr);
    // 调用napi\_is\_arraybuffer接口判断给定入参是否为ArrayBuffer数据
    bool result = false;
    napi\_status status = napi\_is\_arraybuffer(env, args\[0\], &result);
    if (status != napi\_ok) {
        napi\_throw\_error(env, nullptr, "Node-API napi\_is\_arraybuffer fail");
        return nullptr;
    }
    // 将结果转成napi\_value类型返回
    napi\_value returnValue = nullptr;
    napi\_get\_boolean(env, result, &returnValue);
    return returnValue;
}

接口声明

index.d.ts

export const isArrayBuffer: <T>(arrayBuffer: T) => boolean | undefined; // napi\_is\_arraybuffer

ArkTS侧示例代码

// test interface napi\_is\_arraybuffer
try {
  let value = new ArrayBuffer(1);
  let data = "123";
  hilog.info(0x0000, 'testTag', 'Test Node-API napi\_is\_arraybuffer: %{public}s',
    testNapi.isArrayBuffer(value));
  hilog.info(0x0000, 'testTag', 'Test Node-API napi\_is\_arraybuffer: %{public}s',
    testNapi.isArrayBuffer(data));
  // ...
} catch (error) {
  hilog.error(0x0000, 'testTag', 'Test Node-API napi\_is\_arraybuffer error: %{public}s',
    error.message);
  // ...
}

输出日志：

Test Node-API napi\_is\_arraybuffer: true

Test Node-API napi\_is\_arraybuffer: false

#### \[h2\]napi\_get\_arraybuffer\_info

获取ArrayBuffer的底层数据缓冲区和长度。接口只能处理ArrayBuffer类型，请勿将其他类型传入接口。若想从Uint8Array类型中取到ArrayBuffer，需要在ArkTS侧执行.buffer操作。

cpp部分代码

// napi\_get\_arraybuffer\_info
static napi\_value GetArrayBufferInfo(napi\_env env, napi\_callback\_info info)
{
    size\_t argc = 1;
    napi\_value args\[1\] = {nullptr};
    napi\_get\_cb\_info(env, info, &argc, args, nullptr, nullptr);
    // 检查参数是否为ArrayBuffer
    bool isArrayBuffer = false;
    napi\_is\_arraybuffer(env, args\[0\], &isArrayBuffer);
    if (!isArrayBuffer) {
        napi\_throw\_type\_error(env, nullptr, "Argument must be an ArrayBuffer");
        return nullptr;
    }

    void \*data = nullptr;
    size\_t byteLength = 0;
    // 获取ArrayBuffer的底层数据缓冲区和长度
    napi\_status status = napi\_get\_arraybuffer\_info(env, args\[0\], &data, &byteLength);
    if (status != napi\_ok) {
        napi\_throw\_error(env, nullptr, "Failed to get ArrayBuffer info");
        return nullptr;
    }
    // 创建结果对象
    napi\_value result = nullptr;
    napi\_create\_object(env, &result);
    // 创建数据缓冲区的字节长度属性
    napi\_value byteLengthValue = nullptr;
    napi\_create\_uint32(env, byteLength, &byteLengthValue);
    napi\_set\_named\_property(env, result, "byteLength", byteLengthValue);
    napi\_value bufferData = nullptr;
    void \*newData = nullptr;
    napi\_create\_arraybuffer(env, byteLength, &newData, &bufferData);
    memcpy(newData, data, byteLength);
    napi\_set\_named\_property(env, result, "buffer", bufferData);
    return result;
}

接口声明

index.d.ts

export class ArrayBufferInfo {
  byteLength: number;
  buffer: ArrayBuffer;
}
export const getArrayBufferInfo: (data: ArrayBuffer) => ArrayBufferInfo | undefined; // napi\_get\_arraybuffer\_info

ArkTS侧示例代码

// test interface napi\_get\_arraybuffer\_info
try {
  let typedArray = new Uint8Array(\[1, 2, 3, 4, 5\]);
  let buffer = typedArray.buffer;
  let result = testNapi.getArrayBufferInfo(buffer) as testNapi.ArrayBufferInfo;
  let resBuffer = new Uint8Array(result.buffer);
  hilog.info(0x0000, 'testTag', 'Test Node-API get\_arrayBuffer\_info byteLength: %{public}d buffer: %{public}s', result.byteLength, JSON.stringify(resBuffer));
} catch (error) {
  hilog.error(0x0000, 'testTag', 'Test Node-API get\_arrayBuffer\_info error: %{public}s', error.message);
}

输出日志：

Test Node-API napi\_get\_arraybuffer\_info byteLength: 5 buffer: {"0":1,"1":2,"2":3,"3":4,"4":5}

#### \[h2\]napi\_detach\_arraybuffer

分离给定ArrayBuffer的底层数据。

#### \[h2\]napi\_is\_detached\_arraybuffer

判断给定的ArrayBuffer是否已被分离。

cpp部分代码

// napi\_detach\_arraybuffer
static napi\_value DetachedArrayBuffer(napi\_env env, napi\_callback\_info info)
{
    // 调用napi\_detach\_arraybuffer接口分离给定ArrayBuffer的底层数据
    size\_t argc = 1;
    napi\_value args\[1\] = {nullptr};
    napi\_get\_cb\_info(env, info, &argc, args, nullptr, nullptr);
    napi\_value arrayBuffer = args\[0\];
    napi\_detach\_arraybuffer(env, arrayBuffer);
    // 将分离后的arraybuffer传出去
    return arrayBuffer;
}

// napi\_is\_detach\_arraybuffer
static napi\_value IsDetachedArrayBuffer(napi\_env env, napi\_callback\_info info)
{
    // 调用napi\_is\_detached\_arraybuffer判断给定的arraybuffer是否已被分离
    size\_t argc = 1;
    napi\_value args\[1\] = {nullptr};
    napi\_get\_cb\_info(env, info, &argc, args, nullptr, nullptr);
    napi\_value arrayBuffer = args\[0\];
    bool result = false;
    napi\_is\_detached\_arraybuffer(env, arrayBuffer, &result);
    // 将返回值通过napi\_get\_boolean接口转成napi\_value传出去做打印
    napi\_value returnValue;
    napi\_get\_boolean(env, result, &returnValue);
    return returnValue;
}

接口声明

index.d.ts

export const detachedArrayBuffer: (buffer:ArrayBuffer) => ArrayBuffer; // napi\_detach\_arraybuffer
export const isDetachedArrayBuffer: (arrayBuffer: ArrayBuffer) => boolean; //napi\_is\_detached\_arraybuffer

ArkTS侧示例代码

// test interface napi\_detach\_arraybuffer and napi\_is\_detached\_arraybuffer
try {
  const bufferArray = new ArrayBuffer(8);
  hilog.info(0x0000, 'testTag', 'Test Node-API napi\_is\_detached\_arraybuffer one: %{public}s',
    testNapi.isDetachedArrayBuffer(bufferArray));
  hilog.info(0x0000, 'testTag', 'Test Node-API napi\_is\_detached\_arraybuffer two: %{public}s ',
    testNapi.isDetachedArrayBuffer(testNapi.detachedArrayBuffer(bufferArray)));
  // ...
} catch (error) {
  hilog.error(0x0000, 'testTag', 'Test Node-API napi\_is\_detached\_arraybuffer error: %{public}s',
    error.message);
  // ...
}

输出日志：

Test Node-API napi\_is\_detached\_arraybuffer one: false

Test Node-API napi\_is\_detached\_arraybuffer two: true

#### \[h2\]napi\_create\_arraybuffer

用于在C/C++中创建一个具有指定字节长度的ArkTS ArrayBuffer对象，如果调用者想要直接操作缓冲区，则可以选择将底层缓冲区返回给调用者。要从ArkTS写入此缓冲区，需要创建类型化数组或DataView对象。

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/c5/v3/XNlPOMl4R1eu_dgQ832NqA/caution_3.0-zh-cn.png?HW-CC-KV=V1&HW-CC-Date=20260709T132815Z&HW-CC-Expire=86400&HW-CC-Sign=5306C755D619B061A3ABCA2F2EEBCB2CB51DEB1F72F9AFCD833BC6CC3555076D)

napi\_create\_arraybuffer在byte\_length为0或超大值时，data返回值将为nullptr。因此在对data进行使用前，有必要对其进行判空。

cpp部分代码

// napi\_create\_arraybuffer
static napi\_value CreateArrayBuffer(napi\_env env, napi\_callback\_info info)
{
    size\_t argc = 1;
    napi\_value argv\[1\] = {nullptr};
    napi\_value result = nullptr;
    // 解析传递的参数
    napi\_get\_cb\_info(env, info, &argc, argv, nullptr, nullptr);
    int32\_t value;
    size\_t length;
    // 将ArkTS侧传递的参数转换为size\_t类型，作为napi\_create\_arraybuffer的参数
    napi\_get\_value\_int32(env, argv\[0\], &value);
    length = size\_t(value);
    void \*data = nullptr;
    // 创建一个新的ArrayBuffer
    napi\_create\_arraybuffer(env, length, &data, &result);
    if (data != nullptr) {
        // 确保安全后才能使用data进行操作
    } else {
        // 处理内存分配失败的情况
        OH\_LOG\_ERROR(LOG\_APP, "Failed to allocate memory for ArrayBuffer");
        return nullptr;
    }
    // 返回ArrayBuffer
    return result;
}

接口声明

index.d.ts

export const createArrayBuffer: (size: number) => ArrayBuffer; // napi\_create\_arraybuffer

ArkTS侧示例代码

// test interface napi\_create\_arraybuffer
hilog.info(0x0000, 'testTag', 'Test Node-API napi\_create\_arraybuffer:%{public}s',
  testNapi.createArrayBuffer(10).toString());

以上代码如果要在native cpp中打印日志，需在CMakeLists.txt文件中添加以下配置信息（并添加头文件：#include "hilog/log.h"）：

// CMakeLists.txt
add\_definitions( "-DLOG\_DOMAIN=0xd0d0" )
add\_definitions( "-DLOG\_TAG=\\"testTag\\"" )
target\_link\_libraries(entry PUBLIC libace\_napi.z.so libhilog\_ndk.z.so)

输出日志：

Test Node-API napi\_create\_arraybuffer:\[object ArrayBuffer\]

#### 注意事项

*   **生命周期和内存管理**：在使用Node-API处理ArrayBuffer时，需注意，void\*类型的buffer数据段生命周期由引擎管理，[不允许用户自己delete，否则会double free](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/napi-guidelines#防止重复释放获取的buffer)。
*   **需注意申请buffer大小**：当byte\_length很大时，分配失败并不会抛异常，参数data指向的内存为nullptr。建议对\*data == nullptr做严格判断，并对超大byte\_length做限额检验，避免OOM。