使用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函数,这个 ...
随机推荐
- Python之禅的翻译和解释
The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit ...
- 推箱子 HDU1254 (bfs)
较难的bfs 有两种方法做 一种双重bfs: 主bfs是箱子 还要通过dfs判断人是否能到箱子后面 用inmap函数的好处.. 箱子要用三位数组来标记 因为箱子可以回到原来到过的地方 因为推的 ...
- (转)获取 request 中用POST方式"Content-type"是"application/x-www-form-urlencoded;charset=utf-8"发送的 json 数据
request中发送json数据用post方式发送Content-type用application/json;charset=utf-8方式发送的话,直接用springMVC的@RequestBody ...
- 大数据系列博客之 --- 深入简出 Shell 脚本语言(提升篇)
首先声明,此系列shell系列博客分为四篇发布,分别是: 基础篇:https://www.cnblogs.com/lsy131479/p/9914747.html 提升篇:https://www.cn ...
- 利用ApiPost接口调试与文档生成工具,提升前、后端工作效率
什么是ApiPost? 场景1: 对于我们后端程序员,常常会写一些接口(APIs),但是在前端尚未调用之前,我们必须先自己测试下这个接口是不是正确返回了预定结果.对于一个GET请求的接口还好,我们可以 ...
- C# DataGridView插入DB
public static bool ContrastColumns(DataColumnCollection co1, DataGridViewColumnCollection co2) { boo ...
- AJP认证信息爆破ajp_brute
AJP认证信息爆破ajp_brute 一旦AJP服务启用身份认证后,就可以使用Nmap提供的ajp-brute脚本实施爆破.该脚本使用Nmap自带的用户名字典和密码字典实施爆破.在破解前,用户应该 ...
- Cordova项目config.xml添加android权限
最近在开发cordova项目,安卓APP需要调用照相机和系统相册,在添加安卓权限的时候,总是报错. 以下是部分config.xml代码 <platform name="android& ...
- C#中的快捷键,可以更方便的编写代码
C#中的快捷键,可以更方便的编写代码 CTRL + SHIFT + B 生成解决方案 CTRL + F7 生成编译 CTRL + O 打开文件 CTRL + SHIFT + O 打开项目 CTRL + ...
- [LintCode/LeetCode]——两数和、三数和、四数和
LintCode有大部分题目来自LeetCode,但LeetCode比较卡,下面以LintCode为平台,简单介绍我AC的几个题目,并由此引出一些算法基础. 1)两数之和(two-sum) 题目编号: ...