使用quicklz缩小程序体积
简述
有一个需求是这样的,写的一个程序内置了一个很大的文件(实际就是抓取epsg.io的内容里面的epsg.io.json),这个文件筛选缩减后还有12MB,如果直接内置到程序中,编译后的程序就很大了。
因为这个程序是一个动态库,而使用upx压缩过的动态库有时候会有一些异常问题出现,所以不考虑使用upx进行压缩。
看到了quicklz后,感觉这是个好东西,于是就用这个来进行压缩,把压缩后的数据写入程序中,使用前进行解压即可。使用这个操作之后,程序大小从12MB缩小为不到1.5MB,效果很明显。
压缩和解压代码
关于quicklz的使用,在http://www.quicklz.com/网站上有比较详细的说明,各个编程语言的接口也都有封装好。
更多的可以参考https://github.com/robottwo/quicklz
压缩代码
压缩的代码很简单,因为我这里只做字符串的,所以压缩率还比较高,可以达到12%左右。
压缩的代码如下:
// 压缩字符串src,返回qlz编码格式的内容
std::string quicklz_compress(const std::string& src)
{
qlz_state_compress state;
memset(&state, 0, sizeof(qlz_state_compress));
std::string dst;
char buffer[4096 + 1024];
for(size_t pos = 0;pos<src.size();pos+=4096) {
size_t len = src.size() - pos;
len = len > 4096 ? 4096 : len;
len = qlz_compress(src.data() + pos, buffer, len, &state);
dst.append(buffer,len);
}
return dst;
}
下面是quiz.c里面进行压缩的代码,可供参考
#include "quicklz.h"
#define MAX_BUF_SIZE 1024*1024
#define BUF_BUFFER 400
#define bool int
#define true 1
#define false 0
int stream_compress(FILE *ifile, FILE *ofile)
{
char *file_data, *compressed;
size_t d, c, fd_size, compressed_size;
qlz_state_compress *state_compress = (qlz_state_compress *)malloc(sizeof(qlz_state_compress));
fd_size = MAX_BUF_SIZE;
file_data = (char*) malloc(fd_size);
// allocate MAX_BUF_SIZE + BUF_BUFFER bytes for the destination buffer
compressed_size = MAX_BUF_SIZE + BUF_BUFFER;
compressed = (char*) malloc(compressed_size);
// allocate and initially zero out the states. After this, make sure it is
// preserved across calls and never modified manually
memset(state_compress, 0, sizeof(qlz_state_compress));
// compress the file using MAX_BUF_SIZE packets.
while((d = fread(file_data, 1, MAX_BUF_SIZE, ifile)) != 0)
{
c = qlz_compress(file_data, compressed, d, state_compress);
// the buffer "compressed" now contains c bytes which we could have sent directly to a
// decompressing site for decompression
fwrite(compressed, c, 1, ofile);
}
free(state_compress);
free(compressed);
free(file_data);
return 0;
}
解压代码
解压的速度很快,对程序运行几乎没有影响,比读取文件快多了。
解压代码如下:
std::string quicklz_decompress(const std::string& qlzdata)
{
qlz_state_decompress state;
memset(&state, 0, sizeof(qlz_state_decompress));
std::string dst;
for(size_t pos = 0;ops < qlzdata.size(); ){
// 获取压缩数据段大小
size_t co_size = qlz_size_compressed(qlzdata.data() + pos);
// 获取该压缩段解压后的大小
size_t de_size = qlz_size_decompressed(qlzdata.data() + pos);
std::string buffer(de_size,0);
qlz_decompress(qlzdata.data()+pos, (char*)buffer.data(),&state);
pos += co_size;
dst.append(buffer);
}
return dst;
}
下面是quiz.c里面进行解压的代码,可供参考
int stream_decompress(FILE *ifile, FILE *ofile)
{
char *file_data, *decompressed;
size_t d, c, dc, fd_size, d_size;
qlz_state_decompress *state_decompress = (qlz_state_decompress *)malloc(sizeof(qlz_state_decompress));
// a compressed packet can be at most MAX_BUF_SIZE + BUF_BUFFER bytes if it
// was compressed with this program.
fd_size = MAX_BUF_SIZE + BUF_BUFFER;
file_data = (char*) malloc(fd_size);
// allocate decompression buffer
d_size = fd_size - BUF_BUFFER;
decompressed = (char*) malloc(d_size);
// allocate and initially zero out the scratch buffer. After this, make sure it is
// preserved across calls and never modified manually
memset(state_decompress, 0, sizeof(qlz_state_decompress));
// read 9-byte header to find the size of the entire compressed packet, and
// then read remaining packet
while((c = fread(file_data, 1, 9, ifile)) != 0)
{
// Do we need a bigger decompressed buffer? If the file was compressed
// with segments larger than the default in this program.
dc = qlz_size_decompressed(file_data);
if (dc > (fd_size - BUF_BUFFER)) {
free(file_data);
fd_size = dc + BUF_BUFFER;
file_data = (char*)malloc(fd_size);
}
// Do we need a bigger compressed buffer?
c = qlz_size_compressed(file_data);
if (c > d_size) {
free (decompressed);
d_size = c;
decompressed = (char*)malloc(d_size);
}
fread(file_data + 9, 1, c - 9, ifile);
d = qlz_decompress(file_data, decompressed, state_decompress);
fwrite(decompressed, d, 1, ofile);
}
free(decompressed);
free(state_decompress);
free(file_data);
return 0;
}
将二进制文件生成C数组程序代码
上面的代码用于压缩和解压qlz数据,但是这些数据还需要生成C风格的数组,于是就写了一个小程序来做转换,代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int c,char** v)
{
if(c != 3){
printf("Usage:%s infile outfile\n",v[0]);
return 0;
}
FILE* fin = fopen(v[1],"rb");
if(!fin){
printf("Error:%s Open Failed\n",v[1]);
return 1;
}
FILE* fout = fopen(v[2],"wb");
if(fout){
size_t len = 0;
unsigned char buffer[16];
char strbuffer[1024] = "const unsigned char carr_xxx[] = {";
fwrite(strbuffer,1,strlen(strbuffer),fout);
while((len = fread(buffer,1 ,sizeof buffer,fin)) != 0){
strbuffer[0] = '\n';
strbuffer[1] = '\t';
for(size_t i = 0, offset = 2; i < len; ++i) {
offset += sprintf(&strbuffer[offset],"%hhu,",buffer[i]);
}
fwrite(strbuffer,1,strlen(strbuffer),fout);
}
if(strbuffer[0] != 'c'){
fseek(fout,-1, SEEK_CUR);
}
strcpy(strbuffer,"\n};\n");
fwrite(strbuffer,1,strlen(strbuffer),fout);
fclose(fout);
}
fclose(fin);
return 0;
}
使用quicklz缩小程序体积的更多相关文章
- 减小Delphi XE5编译出来的程序体积
默认Delphi XE, XE2, XE3,XE4,XE5, XE6 ... 编译出来的程序体积很大. 一般用两个方法可以很大程度上减少程序体积. 一.在工程中用编译指令禁用RTTI 禁用的方法很简单 ...
- 黄聪:优化清理WordPress数据库wp_options表(缩小autoload体积)
使得wp_options表变得庞大的重要原因:无用的RSS Feed Cache.如果你在wp_options表中发现了大量option_name包含“_transient”的数据,那就是它没跑了.先 ...
- 如何为你的微信小程序体积瘦身?
众所周知,微信小程序在发布的时候,对提交的代码有1M大小的限制!所以,如果你正在写一个功能稍微复杂一点的小程序,就必须得时刻小心注意你的代码是不是快触及这个底线了. 在设计一个小程序之初,我们就需要重 ...
- 使用--gc-section编译选项减小程序体积
本周在给程序添加功能的时候,突然发现,我只是写了几个函数,还没调用,size就变大了.这肯定是不行的嘛,没用的函数就应该不链接进来,占用我宝贵的空间. 这种功能,讲道理编译器肯定要支持的,于是搜了一下 ...
- 缩小jquery体积
jQuery 分析 据统计,目前全世界57.3%的网站使用它.也就是说,10个网站里面,有6个使用jQuery.如果只考察使用工具库的网站,这个比例就会上升到惊人的91.7%. 虽然jQuery如此受 ...
- 使用模块化编译缩小 apk 体积
libcocos2dlua.so编译出来有11M多,其中包含了很多不需要的模块,模块化编译,把不需要用到的模块弄成0,体积就小了. 如: 修改D:\codeide\sDiShu2formm\frame ...
- VC++下编译 程序“减肥”
在vc6 和 vs 2008下 编译 以下代码,不更改任何编译设置(vc6 40k , s2008 7k). 一.vc6下,Release 模式 编译处理. 1.去掉不必要的 链接库 工程(Pro ...
- 安全之路 —— 使用Windows全局钩子打造键盘记录器
简介 键盘记录功能一直是木马等恶意软件窥探用户隐私的标配,那么这个功能是怎么实现的呢?在Ring3级下,微软就为我们内置了一个Hook窗口消息的API,也就是SetWindowsHookEx函数,这个 ...
- 使用Windows全局钩子打造键盘记录器
简介 键盘记录功能一直是木马等恶意软件窥探用户隐私的标配,那么这个功能是怎么实现的呢?在Ring3级下,微软就为我们内置了一个Hook窗口消息的API,也就是SetWindowsHookEx函数,这个 ...
随机推荐
- #9 //[SDOI2017]新生舞会
题解: 分数规划+费用流 常数巨大开o2加inline加register还是不行 我也不知道为什么 代码: #include <bits/stdc++.h> using namespace ...
- sum of powers
题意: 考虑所有的可重集{a1,a2,a3....ak} 满足a1+a2+....+ak=n,求所有a1^m+a2^m+a3^m的和 n,m,k<=5000 题解: part1: 考虑f[i][ ...
- 6.Django与Ajax
Ajax 文件夹为Ajaxdemo 向服务器发送请求的途径: 1.浏览器地址栏,默认get请求: 2.form表单: get请求 post请求 3.a标签,超链接(get请求) 4.Ajax请求 特点 ...
- 启用mysql的sql日志
在mysql命令行或者客户端管理工具中执行:SHOW VARIABLES LIKE "general_log%"; 结果: general_log OFFgeneral_log_f ...
- HDU1575-Tr 【矩阵快速幂】(模板题)
<题目链接> 题目大意: A为一个方阵,则Tr A表示A的迹(就是主对角线上各项的和),现要求Tr(A^k)%9973. Input 数据的第一行是一个T,表示有T组数据. 每组数据的第 ...
- 【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-3 蒙特卡罗 (三)
开学人倍忙,趁着第二周周末,我们继续图形相关的博客 Preface 今天我们来介绍一些理论方面的东西,为Monte Carlo 应用到我们的光线追踪器做铺垫 我们今天会介绍两章的东西,因为有一章内容 ...
- go语言学习-接口
Go语言中虽然没有传统面向对象语言中类.集成的概念,不过提供了接口的支持,可以使用接口来使用一些面向对象的特性. 在 go 语言中,的接口有下面几个特点: 可以包含0个或多个方法的签名 只定义方法的签 ...
- 模拟ajax接口返回的数据
{ "status": 0, "hasError": false, "success": true, "errno": ...
- Session失效后所有Ajax请求跳转登录地址
当登录的Session失效后,采用ajax请求数据时会没有反应,这时候应该自动跳转到登录页面,让用户重新登录. 全局配置以下可实现 $(function() { $.ajaxSetup({ compl ...
- 4826: [Hnoi2017]影魔
4826: [Hnoi2017]影魔 https://lydsy.com/JudgeOnline/problem.php?id=4826 分析: 莫队+单调栈+st表. 考虑如何O(1)加入一个点,删 ...