1# 使用Node-API接口进行buffer相关开发
2
3## 简介
4
5在ArkTS中,Buffer是一种用于处理二进制数据的数据类型。
6
7## 基本概念
8
9使用Node-API接口进行buffer相关开发时,使用Buffer对象与ArkTS代码之间进行二进制数据的有效交互,以便在Node-API模块创建、操纵和传递Buffer对象到ArkTS,从而处理和传递二进制数据,比如文件I/O、网络传输等。
10
11- **Buffer对象**:用于表示一段二进制数据的对象。
12- **外部Buffer**:在Node-API模块中创建的Buffer,可以与现有的数据关联起来而不需要复制数据到新的Buffer中。
13
14## 场景和功能使用
15
16以下这些接口用于有效地与ArkTS层进行交互,这使Node-API模块能够更好地处理ArkTS层的二进制数据,比如处理文件I/O、网络传输等操作:
17| 接口 | 描述 |
18| -------- | -------- |
19| napi_create_buffer | 用于创建并获取一个指定大小的ArkTS Buffer。 |
20| napi_create_buffer_copy | 用于创建并获取一个指定大小的ArkTS Buffer,并以给定的入参数据对buffer的缓冲区进行初始化。 |
21| napi_create_external_buffer | 用于创建并获取一个指定大小的ArkTS Buffer,并以给定数据进行初始化,该接口可为Buffer附带额外数据。 |
22| napi_get_buffer_info | 获取ArkTS Buffer底层数据缓冲区及其长度。 |
23| napi_is_buffer | 判断给定ArkTS value是否为Buffer对象。 |
24| napi_create_external_arraybuffer | 用于分配一个附加有外部数据的ArkTS ArrayBuffer。外部ArrayBuffer是一个特殊类型的ArrayBuffer,它持有对外部数据的引用而不实际拥有数据存储。|
25
26## 使用示例
27
28Node-API接口开发流程参考[使用Node-API实现跨语言交互开发流程](use-napi-process.md),本文仅对接口对应C++及ArkTS相关代码进行展示。
29
30### napi_create_buffer
31
32此接口用于创建Buffer对象。Buffer对象是用于在Node-API模块中操作二进制数据的一种特殊类型。
33
34cpp部分代码
35
36```cpp
37#include <string>
38#include "napi/native_api.h"
39
40static napi_value CreateBuffer(napi_env env, napi_callback_info info)
41{
42    std::string str("CreateBuffer");
43    void *bufferPtr = nullptr;
44    size_t bufferSize = str.size();
45    napi_value buffer = nullptr;
46    // 调用napi_create_buffer接口创建并获取一个指定大小的ArkTS Buffer
47    napi_create_buffer(env, bufferSize, &bufferPtr, &buffer);
48    // 将字符串str的值复制到buffer的内存中
49    strcpy((char *)bufferPtr, str.data());
50    return buffer;
51}
52```
53
54接口声明
55
56```ts
57// index.d.ts
58export const createBuffer: () => string;
59```
60
61ArkTS侧示例代码
62
63```ts
64import hilog from '@ohos.hilog'
65import testNapi from 'libentry.so'
66try {
67  hilog.info(0x0000, 'testTag', 'Test Node-API napi_create_buffer: %{public}s', testNapi.createBuffer().toString());
68} catch (error) {
69  hilog.error(0x0000, 'testTag', 'Test Node-API napi_create_buffer error');
70}
71```
72
73### napi_create_buffer_copy
74
75本接口是Node-API中用于创建并复制数据到Buffer对象的函数。它可以在Node-API模块中创建一个新的Buffer对象,并将指定的数据复制到该Buffer对象中。
76
77cpp部分代码
78
79```cpp
80#include <string>
81#include "hilog/log.h"
82#include "napi/native_api.h"
83
84static napi_value CreateBufferCopy(napi_env env, napi_callback_info info)
85{
86    // 要copy的内容
87    std::string str("CreateBufferCopy");
88    napi_value buffer = nullptr;
89    // 调用napi_create_buffer_copy接口创建buffer并将str的内容copy到buffer
90    void* resultData = nullptr;
91    napi_create_buffer_copy(env, str.size(), str.data(), &resultData, &buffer);
92    OH_LOG_INFO(LOG_APP, "Node-API resultData is : %{public}s.", resultData);
93    return buffer;
94}
95```
96
97接口声明
98
99```ts
100// index.d.ts
101export const createBufferCopy: () => string;
102```
103
104ArkTS侧示例代码
105
106```ts
107import hilog from '@ohos.hilog'
108import testNapi from 'libentry.so'
109try {
110  hilog.info(0x0000, 'testTag', 'Test Node-API napi_create_buffer_copy: %{public}s', testNapi.createBufferCopy().toString());
111} catch (error) {
112  hilog.error(0x0000, 'testTag', 'Test Node-API napi_create_buffer_copy error');
113}
114```
115
116### napi_create_external_buffer
117
118当希望在ArkTS中使用现有的Node-API模块内存块,而不需要额外的拷贝时,可以使用napi_create_external_buffer。这将允许ArkTS层直接访问并操作该内存,避免额外的内存分配和拷贝操作。
119
120cpp部分代码
121
122```cpp
123#include <malloc.h>
124#include <string>
125#include "napi/native_api.h"
126
127// 回调函数,用于释放内存
128void FinalizeCallback(napi_env env, void *data, void *hint)
129{
130    if (data == nullptr) {
131        return;
132    }
133    free(data);
134    data = nullptr;
135}
136
137static napi_value CreateExternalBuffer(napi_env env, napi_callback_info info)
138{
139    // 创建一个字符串
140    std::string str("CreateExternalBuffer");
141    // 在堆上分配内存,大小为字符串的长度
142    void* data = malloc(str.size());
143    // 将字符串复制到分配的内存中
144    strcpy((char *)(data), (char*)(str.data()));
145    // 使用napi_create_external_buffer接口创建并获取一个指定大小buffer
146    napi_value buffer = nullptr;
147    napi_create_external_buffer(env, str.size(), data, FinalizeCallback, nullptr, &buffer);
148    return buffer;
149}
150```
151
152接口声明
153
154```ts
155// index.d.ts
156export const createExternalBuffer: () => string;
157```
158
159ArkTS侧示例代码
160
161```ts
162import hilog from '@ohos.hilog'
163import testNapi from 'libentry.so'
164try {
165  hilog.info(0x0000, 'testTag', 'Test Node-API napi_create_external_buffer: %{public}s', testNapi.createExternalBuffer()
166    .toString());
167} catch (error) {
168  hilog.error(0x0000, 'testTag', 'Test Node-API napi_create_external_buffer error');
169}
170```
171
172### napi_get_buffer_info
173
174在ArkTS中需要对Buffer对象中的数据执行特定的操作时,可以使用此接口来获取指向数据的指针和数据长度。这样可以在Node-API模块直接对数据进行操作,而无需进行数据的拷贝。
175
176cpp部分代码
177
178```cpp
179#include <string>
180#include "napi/native_api.h"
181
182static napi_value GetBufferInfo(napi_env env, napi_callback_info info)
183{
184    // 创建一个字符串
185    std::string str("GetBufferInfo");
186    napi_value buffer = nullptr;
187    void *bufferPtr = nullptr;
188    size_t bufferSize = str.size();
189    napi_create_buffer(env, bufferSize, &bufferPtr, &buffer);
190    strcpy((char *)bufferPtr, str.data());
191
192    // 获取Buffer的信息
193    void *tmpBufferPtr = nullptr;
194    size_t bufferLength = 0;
195    napi_get_buffer_info(env, buffer, &tmpBufferPtr, &bufferLength);
196
197    // 创建一个新的ArkTS字符串来保存Buffer的内容并返出去
198    napi_value returnValue = nullptr;
199    napi_create_string_utf8(env, (char*)tmpBufferPtr, bufferLength, &returnValue);
200    return returnValue;
201}
202```
203
204接口声明
205
206```ts
207// index.d.ts
208export const getBufferInfo: () => string;
209```
210
211ArkTS侧示例代码
212
213```ts
214import hilog from '@ohos.hilog'
215import testNapi from 'libentry.so'
216try {
217  hilog.info(0x0000, 'testTag', 'Test Node-API napi_get_buffer_info: %{public}s', testNapi.getBufferInfo().toString());
218} catch (error) {
219  hilog.error(0x0000, 'testTag', 'Test Node-API napi_get_buffer_info error');
220}
221```
222
223### napi_is_buffer
224
225判断给定ArkTS value是否为Buffer对象。
226
227cpp部分代码
228
229```cpp
230#include <string>
231#include "napi/native_api.h"
232
233static napi_value IsBuffer(napi_env env, napi_callback_info info)
234{
235    // 创建一个Buffer对象
236    std::string str = "buffer";
237    napi_value buffer = nullptr;
238    napi_create_buffer(env, strlen(str.data()), (void **)(str.data()), &buffer);
239
240    // 调用napi_is_buffer接口判断创建的对象是否为buffer
241    bool result = false;
242    napi_is_buffer(env, buffer, &result);
243    // 将结果返回出去
244    napi_value returnValue = nullptr;
245    napi_get_boolean(env, result, &returnValue);
246    return returnValue;
247}
248```
249
250接口声明
251
252```ts
253// index.d.ts
254export const isBuffer: () => boolean;
255```
256
257ArkTS侧示例代码
258
259```ts
260import hilog from '@ohos.hilog'
261import testNapi from 'libentry.so'
262try {
263  hilog.info(0x0000, 'testTag', 'Test Node-API napi_is_buffer: %{public}s', JSON.stringify(testNapi.isBuffer()));
264} catch (error) {
265  hilog.info(0x0000, 'testTag', 'Test Node-API napi_is_buffer error');
266}
267```
268
269### napi_create_external_arraybuffer
270
271分配一个附加有外部数据的ArkTS ArrayBuffer。
272
273cpp部分代码
274
275```cpp
276#include "napi/native_api.h"
277
278typedef struct {
279    uint8_t *data;
280    size_t length;
281} BufferData;
282
283void FinalizeCallback(napi_env env, void *finalize_data, void *finalize_hint)
284{
285    // 获取终结时的数据
286    BufferData *bufferData = static_cast<BufferData *>(finalize_data);
287
288    // 执行清理操作,比如释放资源
289    delete[] bufferData->data;
290    delete bufferData;
291}
292
293napi_value CreateExternalArraybuffer(napi_env env, napi_callback_info info)
294{
295    // 创建一个有五个元素的C++数组
296    uint8_t *dataArray = new uint8_t[5]{1, 2, 3, 4, 5};
297    napi_value externalBuffer = nullptr;
298    BufferData *bufferData = new BufferData{dataArray, 5};
299
300    // 使用napi_create_external_arraybuffer创建一个外部Array Buffer对象,并指定终结回调函数
301    napi_status status =
302        napi_create_external_arraybuffer(env, dataArray, 5, FinalizeCallback, bufferData, &externalBuffer);
303    if (status != napi_ok) {
304        // 处理错误
305        napi_throw_error(env, nullptr, "Node-API napi_create_external_arraybuffer fail");
306        return nullptr;
307    }
308    napi_value outputArray;
309    // 使用napi_create_typedarray创建一个Array对象,并将externalBuffer对象作为参数传入
310    status = napi_create_typedarray(env, napi_int8_array, 5, externalBuffer, 0, &outputArray);
311    if (status != napi_ok) {
312        // 处理错误
313        napi_throw_error(env, nullptr, "Node-API napi_create_typedarray fail");
314        return nullptr;
315    }
316    return outputArray;
317}
318```
319
320接口声明
321
322```ts
323// index.d.ts
324export const createExternalArraybuffer: () => ArrayBuffer | void;
325```
326
327ArkTS侧示例代码
328
329```ts
330import hilog from '@ohos.hilog'
331import testNapi from 'libentry.so'
332
333hilog.info(0x0000, 'testTag', 'Node-API createExternalArraybuffer: %{public}s',
334           JSON.stringify(testNapi.createExternalArraybuffer()));
335```
336
337以上代码如果要在native cpp中打印日志,需在CMakeLists.txt文件中添加以下配置信息(并添加头文件:#include "hilog/log.h"):
338
339```text
340// CMakeLists.txt
341add_definitions( "-DLOG_DOMAIN=0xd0d0" )
342add_definitions( "-DLOG_TAG=\"testTag\"" )
343target_link_libraries(entry PUBLIC libhilog_ndk.z.so)
344```
345