压缩算法_quicklz使用
1 quicklz
quicklz是单片机上一个常见的压缩算法,具体原理没有文档和hash表的相关基础我就不去深究了;
只需要将fileSrc.txt放在桌面,代码可以使用vscode的mingw直接编译;
2 quicklz源码
quicklz源码就一个c文件一个h文件,标准库要求就一个<string.h>;移植起来比较简单,直接包含头文件即可;
https://gitee.com/RT-Thread-Mirror/quicklz
fileSrc.txt
/***Put this file on Desktop as srcFile for quicklz compress;***/
// attention
//1 compress buff no more than 2048 size;
//2 because compressed transmit buff need to read qlz algrorithm parameter together for decompress,
// and parameter will count into decompressed buff;
// may lead to some mistake decompress;
4 quicklz 函数接口
/***main.c**************************************************************************************************/
//vscode直接使用mingw编译的时候没法包含多个c文件编译,需要配置vscode编译路径,不想配先放着;
//所以quicklz.c代码需要放到main函数所在c文件中,不然会查找不到;
#include <stdio.h>
#include <stdlib.h>
#include "quicklz.h"
#define PATH_FILE_SRC "C:/Users/WINDOWS/Desktop/fileSrc.txt"
#define PATH_FILE_CPS "C:/Users/WINDOWS/Desktop/fileCompress.qlz"
#define PATH_FILE_DST "C:/Users/WINDOWS/Desktop/fileDst.txt"
int qlzCompress(void)
{
printf("qlzCompress() \n");
FILE *fsrcFile;
FILE *fcpsFile;
unsigned char psrcTrans[2048] ={0};
unsigned char pdstTrans[2048] ={0};
size_t srcFileLen, cpsFileLen;
qlz_state_compress state_compress;
//fsrcFile handle;
fsrcFile = fopen(PATH_FILE_SRC, "r");
//fsrcFile length;
fseek(fsrcFile, 0, SEEK_END);
srcFileLen = ftell(fsrcFile);
//read fsrcFile >> psrcTrans;
printf("srcFileLen:(d)%08d \n",srcFileLen);
fseek(fsrcFile, 0, SEEK_SET);
fread(psrcTrans, sizeof(char), srcFileLen, fsrcFile);
//for(int i =0; i<srcFileLen;i++) printf("%c",psrcTrans[i]); printf("\n");
//fcpsFile handle;
fcpsFile = fopen(PATH_FILE_CPS, "w");
//compress psrcTrans >> pdstTrans;
cpsFileLen = qlz_compress(psrcTrans, pdstTrans, srcFileLen, &state_compress);
printf("cpsFileLen:(d)%08d \n",cpsFileLen);
fwrite(pdstTrans, sizeof(char), cpsFileLen, fcpsFile);
fclose(fsrcFile);
fclose(fcpsFile);
return 0;
}
int qlzDecompress(void)
{
printf("qlzDecompress() \n");
FILE *fcpsFile;
FILE *fdstFile;
unsigned char *pcpsTrans;
unsigned char *pdstTrans;
qlz_state_decompress state_decompress;
unsigned int cpsFileLen;
unsigned int decpsFileLen;
//fcpsFile handle;
fcpsFile = fopen(PATH_FILE_CPS, "r");
//fcpsFile length;
fseek(fcpsFile, 0, SEEK_END);
cpsFileLen = ftell(fcpsFile);
//pcpsTrans buff
pcpsTrans = (unsigned char *)malloc(cpsFileLen);
if(pcpsTrans==NULL){
printf("malloc cps buff fail. \n");
return -2;
}
//read fcpsFile >> pcpsTrans;
printf("cpsFileLen:(d)%08d \n",cpsFileLen);
fseek(fcpsFile, 0, SEEK_SET);
fread(pcpsTrans, sizeof(char), cpsFileLen, fcpsFile);
//for(int i =0;i< cpsFileLen;i++) printf("%02x ",pcpsTrans[i]); printf("\n");
//pdstTrans length;
decpsFileLen = qlz_size_decompressed(pcpsTrans);
pdstTrans = (unsigned char *)malloc(decpsFileLen);
if(pdstTrans ==NULL){
printf("malloc pdstTrans fail. \n");
return -3;
}
//bcz pcpsTrans read some more qlz para,
//so after decompress will have some more space empty in fileDst.txt? bug leave;
printf("decpsFileLen:(d)%08d \n",decpsFileLen);
decpsFileLen = qlz_decompress(pcpsTrans, pdstTrans, &state_decompress);
fdstFile = fopen(PATH_FILE_DST, "w");
fwrite(pdstTrans, sizeof(char), decpsFileLen, fdstFile);
fclose(fcpsFile);
fclose(fdstFile);
free(pcpsTrans);
free(pdstTrans);
return 0;
}
int main()
{
printf("hello \n");
//文件压缩完之后会多出部分qlz的参数,分配内存时需要考虑;
//因为解压时是通过读取文件长度来解压的,所以解压后结尾部分会把这部分多出的也解压了;qlz本身小bug??
//这个bug的解决办法是在使用数据的时候只读取解压长度的数据,丢弃掉多余字节;
//所以在使用数据的时候,需要通过解压前数据长度来使用;
//上面的接口函数只是压缩解压,不涉及数据处理使用;
//qlz解压最大不超过4096,需要考虑;
//函数内数组不要超出栈空间大小;
qlzCompress();
qlzDecompress();
return 0;
}
5 文件操作读写模式
前两列判断fopen的操作;后两列判断如果可以执行当前函数操作的话pfile的文件偏移位置;
需要注意的是图中斜杆部分读写无此操作,但执行不会报错,导致不容易发现bug,
通过判断fopen、fread、fwrite返回值来判断文件操作是否成功失败,可以提高代码的健壮性和稳定性;
6 小结
这个接口主要还有三个地方需要优化的;
一是vscode编辑器配置多个c文件编译的问题,但是我懒的配置了,先放着吧;
二是解压成源文件之后,解压出来的文件结尾虽然没有数据丢失但是会有部分空格多余,需要丢弃,先放着吧;
三是读写接口可以优化,加上返回值判断,也放着把;