HarmonyOS 鸿蒙Next:如何引用zlib标准库,ohos.zlib仅支持zip指定文件或文件夹,如何对字符串执行解压缩操作?

发布于 1周前 作者 phonegap100 来自 鸿蒙OS

HarmonyOS 鸿蒙Next:如何引用zlib标准库,ohos.zlib仅支持zip指定文件或文件夹,如何对字符串执行解压缩操作?

目前鸿蒙提供的api只能针对一个沙箱路径做zip的解压缩操作

在实际的开发中,我们往往需要对给定的数据做对应的解压缩操作

是否只能通过引用zlib标准库,打包成功xxx.so,再自行开发arkts接口操作?

12 回复

已实现。思路如下:

采用NAPI编程,在C/C++文件中实现gzip的解压缩方法,C/C++有现成的解压缩方法,

编写对应的CMakeLists.txt文件,导出xxx.so

这里需要注意的是,需要在C/C++中创建异步线程,毕竟解压缩是耗时操作。

楼主这个有仓库吗,很有参考价值
楼主有关于zstd解压缩的资料吗?万分感谢
let Zip = await zlib.createZip() 
Zip.compress() 和 Zip.uncompress() 可以处理ArrayBuffer

这个能弄吗,我怎么一直报 The parameter check failed 错误?

实现了压缩的同步和异步,然后导出接口为:

// gzip压缩字符串
export function getGzipSync(source: string) : ArrayBuffer;
export function getGzip(value: string, callback: (result: ArrayBuffer) => void): void;
export function getGzip(value: string): Promise<ArrayBuffer>;
// gzip解压缩
export function getUnGzipSync(buffer: ArrayBuffer) : ArrayBuffer;

HarmonyOS的开发者模式提供了很多实用的工具,方便我们进行调试和优化。

上面是我完整的gzip的实现,可以直接使用
#include "sgzip.h"
#include "asyncwork.h"
#include <cstddef>
#include <stdlib.h>
#include <sys/stat.h>
#include <zlib.h>
#include <js_native_api.h>
#include <node_api.h>
#include <thread>
#include "napiutil.h"


static int sig_compress(char *in_str, char **out_buf, size_t *out_len);


// 定义异步线程执行中需要的上下文环境
struct GzipContext {
// 异步 worker
napi_async_work work;
// 对应 JS 端的 callback 函数
napi_ref callback;
// 对应 JS 端的 promise 对象
napi_deferred promise;
// 传递进来的参数
char *in_str;
// 计算后的结果
char *out_buf;
size_t out_len;
};

// 在子线程中执行
static void sig_doInBackground(napi_env env, void *data) {
GzipContext *ctx = (GzipContext *)data;
// 执行gzip压缩
size_t out_len;
char *out_buf;
sig_compress(ctx->in_str, &out_buf, &out_len);
// 计算后的字存储到 result 中
ctx->out_buf = out_buf;
ctx->out_len = out_len;
}

// 切换到主线程
static void sig_onPostExecutor(napi_env env, napi_status status, void *data) {
GzipContext *ctx = (GzipContext *)data;

// 创建一个Buffer来保存输出数据
napi_value returnValue;
void *out_data = nullptr;
if (napi_ok != napi_create_arraybuffer(env, ctx->out_len, &out_data, &returnValue)) {
delete ctx;
ctx = nullptr;
napi_throw_error(env, "-111", "napi_create_arraybuffer: error");
return;
}
memcpy(out_data, ctx->out_buf, ctx->out_len);
if (ctx->callback) {
// 取出缓存的 js 端的 callback
napi_value callback;
if (napi_ok != napi_get_reference_value(env, ctx->callback, &callback)) {
delete ctx;
ctx = nullptr;
napi_throw_error(env, "-111", "napi_get_reference_value error");
return;
}
napi_value tempValue;
// 调用 callback,把值回调给 JS 端
napi_call_function(env, nullptr, callback, 1, &returnValue, &tempValue);
// 删除 callback
napi_delete_reference(env, ctx->callback);
} else if (ctx->promise) {
// 以 promise 的形式回调数据
if (napi_ok != napi_resolve_deferred(env, ctx->promise, returnValue)) {
delete ctx;
ctx = nullptr;
napi_throw_error(env, "-111", "napi_resolve_deferred error");
}
}
// 删除异步任务并释放资源
napi_delete_async_work(env, ctx->work);
delete ctx;
ctx = nullptr;
}


// 异步
napi_value sig_GzipAsync(napi_env env, napi_callback_info info) {
// 1、从info中取出JS传递过来的参数放入args
size_t argc = 2;
napi_value args[2] = {nullptr};
if (napi_ok != napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)) {
napi_throw_error(env, "-1001", "napi_get_cb_info error");
return nullptr;
}
size_t length = 0;
char *buffer;
napi_value result = Sig_StringValue(env, args[0], &buffer, &length);
// 7、读取 JS 有没有传递 callback,如果 callback 为 null 就表示是 promise 的回调方式
napi_valuetype callbackType = napi_undefined;
napi_status callbackStatus = napi_typeof(env, args[1], &callbackType);
if (napi_ok != callbackStatus && napi_invalid_arg != callbackStatus) {
delete[] buffer;
buffer = nullptr;
napi_throw_error(env, "-1007", "napi_typeof function error");
return nullptr;
}
// 8、创建一个异步线程需要的数据 model,把传递过来的参数加入进去做下缓存
GzipContext *ctx = new GzipContext();
ctx->in_str = buffer;

SigAsyncWorkContext *sigctx = nullptr;
// 9、判断是 callback 的回调方式还是 promise 的回调方式
if (napi_function == callbackType) {
sigctx = SigAsyncCallbackWork(env, args[1], sig_doInBackground, sig_onPostExecutor, (void *)ctx);
} else {
// promise 的回调方式,创建一个 Promise 的引用
sigctx = SigAsyncPromiseWork(env, sig_doInBackground, sig_onPostExecutor, (void *)ctx);
}
if (sigctx == nullptr) {
delete[] buffer;
delete ctx;
buffer = nullptr;
ctx = nullptr;
napi_throw_error(env, "-1008", "napi_create_reference error");
return nullptr;
}
// 缓存 callback
ctx->callback = sigctx->callback;
// 缓存 promise
ctx->promise = sigctx->promise;
return sigctx->returnValue;
}

// 同步
napi_value sig_GzipSync(napi_env env, napi_callback_info info) {
size_t argc = 1;
napi_value args[1] = {nullptr};
if (napi_ok != napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)) {
napi_throw_error(env, NULL, "napi_get_cb_info error");
}

size_t length = 0;
char *buffer;
napi_value result = Sig_StringValue(env, args[0], &buffer, &length);

if (napi_ok != napi_get_value_string_utf8(env, result, buffer, length + 1, &length)) {
free(buffer);
return nullptr;
}
// 7、执行gzip压缩
size_t out_len;
char *out_buf;
sig_compress(buffer, &out_buf, &out_len);

// 创建一个Buffer来保存输出数据
napi_value output_buffer;
void *data = nullptr;
if (napi_ok != napi_create_arraybuffer(env, out_len, &data, &output_buffer)) {
free(out_buf);
free(buffer);
return nullptr;
}
memcpy(data, out_buf, out_len);
// 9、资源清理
free(out_buf);
free(buffer);
return output_buffer;
}


// 同步
napi_value sig_UnGzipSync(napi_env env, napi_callback_info info) {
size_t argc = 1;
napi_value args[1] = {nullptr};
if (napi_ok != napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)) {
napi_throw_error(env, NULL, "napi_get_cb_info error");
}
napi_value array_buffer = Sig_ArrayBufferValue(env, args[0]);
char *input;
size_t input_length;
if (napi_ok != napi_get_buffer_info(env, array_buffer, (void **)&input, &input_length)) {
napi_throw_error(env, NULL, "Decompression napi_get_buffer_info failed");
}
size_t buff_size = input_length * 15; // 假设的大小,应该从实际数据中估算
void *uncompressed_data = malloc(buff_size);
if (uncompressed_data == nullptr) {
free(uncompressed_data);
napi_throw_error(env, NULL, "Decompression malloc failed");
}
// 解压缩数据
uLongf uncompressed_length = buff_size;
int result = uncompress((Bytef *)uncompressed_data, &uncompressed_length, (const Bytef *)input, input_length);
napi_value output_buffer;
if (result != Z_OK) {
// 解压缩失败的处理逻辑
free(uncompressed_data);
napi_throw_error(env, NULL, "Decompression failed");
}
void *data = nullptr;
if (napi_ok != napi_create_arraybuffer(env, uncompressed_length, &data, &output_buffer)) {
free(uncompressed_data);
napi_throw_error(env, NULL, "napi_create_arraybuffer failed");
}
memcpy(data, uncompressed_data, uncompressed_length);
free(uncompressed_data);
return output_buffer;
}



static int sig_compress(char *in_str, char **out_buf, size_t *out_len) {
// 7、执行gzip压缩
size_t input_length = strlen(in_str);
*out_len = compressBound(input_length);
*out_buf = new char[*out_len];
return compress((Bytef *) *out_buf, &(*out_len), (Bytef *)in_str, input_length);
}
楼主实现了数据流压缩解压缩了么?可以分享下么。
伟大的楼主万岁!我这边也有这个需求,我需要解压的数据是接口回传的。楼主能发个demo出来吗?或者再具体讲讲,谢谢!

在HarmonyOS(鸿蒙)中,若ohos.zlib库直接支持的是对文件或文件夹的ZIP操作,而你需要对字符串进行解压缩,你可能需要手动将字符串数据转换为适合zlib处理的字节流格式(如先将其转换为字节数组)。

鸿蒙系统可能未直接提供对字符串解压缩的API,但你可以使用zlib的底层API(如inflate函数)来实现这一功能。你需要设置正确的输入缓冲区(字符串转换的字节数组)和输出缓冲区,并管理好内存和状态。

如果问题依旧没法解决请加我微信,我的微信是itying888。

回到顶部