鸿蒙5.0实战案例:基于原生能力的压缩与解压缩能力

往期推文全新看点(文中附带全新鸿蒙5.0全栈学习笔录)

✏️ 鸿蒙(HarmonyOS)北向开发知识点记录~

✏️ 鸿蒙(OpenHarmony)南向开发保姆级知识点汇总~

✏️ 鸿蒙应用开发与鸿蒙系统开发哪个更有前景?

✏️ 嵌入式开发适不适合做鸿蒙南向开发?看完这篇你就了解了~

✏️ 对于大前端开发来说,转鸿蒙开发究竟是福还是祸?

✏️ 鸿蒙岗位需求突增!移动端、PC端、IoT到底该怎么选?

✏️ 记录一场鸿蒙开发岗位面试经历~

✏️ 持续更新中......


一、场景描述

概览、常用图片编码格式比对及系统支持情况

压缩格式 简介 系统支持/使用方式
zip 普及率高,适用范围也最广,压缩速度相比rar快一些 ArkTs支持,可通过zlib实现,jszip
rar rar格式比zip更能够提供较好的压缩率,但压缩速度也相对慢一些 三方库支持,通过Unrar实现
7z 压缩率相对前两种最大,但速度也最慢 三方库支持,通过commons-compress实现
brotli 无损压缩算法,主要目标是压缩 Internet 上的数据 三方库支持,通过commons-compress实现
tar 简单封装,被称为归档文件,只是简单的将文件组装到一个.tar的文件内,并没有太多文件体积的减少,仅仅是简单的封装 三方库支持,通过commons-compress实现
gzip .gz:使用gzip算法将文件压缩到一个文件,极大的减少压缩后的体积 三方库支持,通过三方库pako实现

ArkTs侧:

场景一:压缩与解压rawfile目录下的文件,由于在resource/rawfile目录下存放的文件,没有对外暴露的沙箱路径,无法使用文件管理接口或以沙箱路径形式处理,因此需要将rawfile下文件通过fs拷贝进沙箱目录下,再使用 zlib 进行压缩与解压。

场景二:压缩与解压resfile下的文件,通过getContext().resourceDir获取到该路径下的文件,再使用zlib进行压缩与解压。

Native侧:

当前鸿蒙暂无native的压缩与解压接口,本文主要介绍native侧通过zlib实现压缩与解压。

二、方案描述

ArkTs侧

方案

1)通过resourceManager.getRawFileContent获取到rawfile下的文件;

2)然后通过fs将rawfile文件内容copy到沙箱路径;

3)最后使用zlib.decompressFile对沙箱路径下的压缩文件进行解压。

效果图

核心代码

复制代码
function resfileZlibDecompress() {

getContext().resourceManager.getRawFileContent('file1.zip', (_err, value) => {

//将rawfile下的文件拷贝至沙箱下,沙箱路径:/data/storage/el2/base/haps/entry/filesfile1.zip

let myBuffer: ArrayBufferLike = value.buffer

let filePath = getContext().filesDir + "file1.zip";

let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);

let writeLen = fs.writeSync(file.fd, myBuffer);

fs.closeSync(file);

let outFileDir = getContext().filesDir;

let options: zlib.Options = {

level: zlib.CompressLevel.COMPRESS_LEVEL_DEFAULT_COMPRESSION

};

//解压沙箱下的文件

try {

zlib.decompressFile(filePath, outFileDir, options, (errData: BusinessError) => {

if (errData !== null) {

console.error(`errData is errCode:${errData.code} message:${errData.message}`);

}

})

} catch (errData) {

let code = (errData as BusinessError).code;

let message = (errData as BusinessError).message;

console.error(fs.accessSync(filePath)+`errData is errCode:${code} message:${message}`);

}

})

}

2.压缩rawfile目录下的文件

方案

思路同rawfile解压,用到的方法:resourceManager.getRawFileContent、fs、zlib.compressFile

核心代码

复制代码
getContext().resourceManager.getRawFileContent('file1.txt', (_err, value) => {

let myBuffer: ArrayBufferLike = value.buffer

//将rawfile下的文件拷贝至沙箱下,沙箱路径:/data/storage/el2/base/haps/entry/files/file1.txt

let filePath = getContext().filesDir + "/file1.txt";

let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);

let writeLen = fs.writeSync(file.fd, myBuffer);

fs.closeSync(file);

//压缩沙箱下的文件

let outFile = getContext().filesDir + '/file1.zip';

let options: zlib.Options = {

level: zlib.CompressLevel.COMPRESS_LEVEL_DEFAULT_COMPRESSION,

memLevel: zlib.MemLevel.MEM_LEVEL_DEFAULT,

strategy: zlib.CompressStrategy.COMPRESS_STRATEGY_DEFAULT_STRATEGY

};

zlib.compressFile(filePath, outFile, options)

})

方案

通过 getContext().resourceDir获取resfile目录下文件,再使用zlib.decompressFile对文件进行解压

效果图

核心代码

复制代码
let inFile = getContext().resourceDir + '/file1.zip';

let outFile = getContext().filesDir;

let options: zlib.Options = {

level: zlib.CompressLevel.COMPRESS_LEVEL_DEFAULT_COMPRESSION

};

//解压沙箱下的文件

zlib.decompressFile(inFile, outFile, options)

方案

思路同resfile解压,用到的方法:zlib.compressFile

核心代码

复制代码
let inFile = getContext().resourceDir + '/file1.txt';

let outFile = getContext().filesDir + "/file1.zip";

let options: zlib.Options = {

level: zlib.CompressLevel.COMPRESS_LEVEL_DEFAULT_COMPRESSION,

memLevel: zlib.MemLevel.MEM_LEVEL_DEFAULT,

strategy: zlib.CompressStrategy.COMPRESS_STRATEGY_DEFAULT_STRATEGY

};

//压缩沙箱下的文件

zlib.compressFile(inFile, outFile, options)

native侧

zlib库进行gzip压缩

当前ArkTs侧zlib暂不支持gzip压缩,可以使用基础库压缩,参考 zlib Usage Example 。

方案

1)首先初始化z_stream结构体,然后设置输入数据和输出buffer的信息。

2)接着使用deflateInit2函数初始化,并使用deflate函数进行压缩。如果输出buffer不足以存储所有压缩数据,则进行拓容并重复压缩的过程,直到所有数据压缩完毕。

3)最后,返回压缩后的数据和数据大小,并使用deflateEnd函数释放。

头文件:zlib.h

核心代码

复制代码
char* compressToGzip(const char *input, int inputSize, int* outputSize) {

z_stream zs;

// 初始化 (主要用于开发者自定义内存管理, 此处不使用, 应用有诉求可参考:https://www.zlib.net/manual.html)

zs.zalloc = Z_NULL; // 用于分配内部状态

zs.zfree = Z_NULL; // 用于释放内部状态

zs.opaque = Z_NULL; // 传递给 zalloc、zfree的私有数据对象

// 初始化输入数据

zs.next_in = (Bytef *)input; // 输入数据头

zs.avail_in = (uInt)inputSize; // 输入数据的内存块大小

// 初始化输出buffer

char *compressedData = new char[CHUNK_SIZE];

// 输出头

zs.next_out = (Bytef *)compressedData;

zs.avail_out = (uInt)CHUNK_SIZE;

// 开始压缩(此处使用空的gzip头)

int windowBits = WINDOWS_BITS; // windowBits历史缓冲区的大小,此参数的值越大,压缩效果越好。 范围(8-15)

// 特殊:windowBits加上 16,表示使用gzip头 windowBits加上 32,表示自动识别gzip/zlib头

int memLevel = 8; // memLevel=1使用最小内存但速度较慢,降低压缩比; memLevel=9使用最大内存以获得最佳速度 默认值为8

deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, windowBits, memLevel, Z_DEFAULT_STRATEGY);

// 压缩 尽量一次压缩完毕

deflate(&zs, Z_FINISH);

int chunkCount = 1; // 数据块的个数

// 重复压缩

while (zs.avail_out == 0) {

// 为输出数据 拓容

chunkCount++;

char* newBuffer = new char[CHUNK_SIZE*chunkCount];

// 复制历史数据

memcpy(newBuffer, compressedData, CHUNK_SIZE*(chunkCount-1));

delete[] compressedData;

compressedData = newBuffer;

// 继续压缩

zs.next_out = (Bytef *)(compressedData+CHUNK_SIZE*(chunkCount-1));

zs.avail_out = (uInt)CHUNK_SIZE;

deflate(&zs, Z_FINISH);

}

// 返回结果

*outputSize = zs.total_out;

deflateEnd(&zs);

return compressedData;

}

zlib库进行gzip解压

方案

思路与压缩相同,使用inflateInit2函数初始化zlib库,然后调用inflate进行解压缩,最后调用inflateEnd结束解压。

核心代码

复制代码
char* decompressGzip(const char *input, int inputSize, int* outputSize) {

z_stream zs;

zs.zalloc = Z_NULL;

zs.zfree = Z_NULL;

zs.opaque = Z_NULL;

zs.avail_in = (uInt)inputSize;

zs.next_in = (Bytef *)input;

char *deCompressedData = new char[CHUNK_SIZE];

zs.avail_out = (uInt)CHUNK_SIZE;

zs.next_out = (Bytef *)deCompressedData;

inflateInit2(&zs, WINDOWS_BITS);

// 解压 尽量一次解压完毕

inflate(&zs, Z_FINISH);

int chunkCount = 1; // 数据块的个数

// 重复解压

while (zs.avail_out == 0) {

// 为输出数据 拓容

chunkCount++;

char* newBuffer = new char[CHUNK_SIZE*chunkCount];

// 复制历史数据

memcpy(newBuffer, deCompressedData, CHUNK_SIZE*(chunkCount-1));

delete[] deCompressedData;

deCompressedData = newBuffer;

// 继续压缩

zs.next_out = (Bytef *)(deCompressedData+CHUNK_SIZE*(chunkCount-1));

zs.avail_out = (uInt)CHUNK_SIZE;

inflate(&zs, Z_FINISH);

}

// 返回结果

*outputSize = zs.total_out;

inflateEnd(&zs);

return deCompressedData;

}
相关推荐
梁下轻语的秋缘6 小时前
每日c/c++题 备战蓝桥杯(P1049 [NOIP 2001 普及组] 装箱问题)
c语言·c++·学习·蓝桥杯
加点油。。。。6 小时前
C语言高频面试题——指针函数和函数指针的区别
c语言·面试
lkbhua莱克瓦248 小时前
用C语言实现——一个中缀表达式的计算器。支持用户输入和动画演示过程。
c语言·开发语言·数据结构·链表·学习方法·交友·计算器
lwewan9 小时前
26考研——存储系统(3)
c语言·笔记·考研
高心星11 小时前
HarmonyOS 5.0应用开发——MVVM模式的应用
harmonyos·mvvm·鸿蒙5.0·备忘录应用
别说我什么都不会11 小时前
【仓颉三方库】工具类—— compress4cj
harmonyos
别说我什么都不会11 小时前
【仓颉三方库】工具类—— uuid4cj
harmonyos
祁同伟.12 小时前
【数据结构 · 初阶】- 堆的实现
c语言·数据结构
夜夜敲码12 小时前
C语言教程(十六): C 语言字符串详解
c语言·开发语言
宋康12 小时前
C语言结构体和union内存对齐
c语言·开发语言