使用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函数,这个 ...
随机推荐
- 事件方法on()
on()方法用来处理事件.jQuery会处理所有浏览器的兼容性问题. on()方法可以指定影响哪个事件,相当于JavaScript中的addEventListener()事件监听. on()方法有两个 ...
- RabbitMQ(一):RabbitMQ 安装与配置(Mac)
一.rabbitmq 安装与配置 安装: brew install rabbitmq # 进入安装目录 cd /usr/local/Cellar/rabbitmq/3.7.12 # 启动 brew s ...
- JAVA开发工程师面试(1)
我已经有很长一段时间没有更新博客了,难道是博主我变懒惰了吗?哎,这样可不行啊,我还有好多知识要学习,要和大家分享.以后我需要更加努力,改掉自己的惰性.本人文采不怎么样,只能是把自己所想的说出来,想和大 ...
- springbank 开发日志 一次因为多线程问题导致的applicationContext.getBean()阻塞
几天前遇到的这个问题.由于交易是配置的,不同的交易是同一个类的不同实例,所以不可能提前将其以@autowired类似的方式注入到需要的类中 <op:transaction id="Re ...
- Ubuntu 安装 OpenMPI
1. 下载OpenMPI 在官网上下载最新版本的安装包,如:openmpi-1.8.4.tar.gz 2. 解压并进行配置 tar -zxvf openmpi-3.0.0.tar.gz cd open ...
- ThreadPoolExecutor线程池的分析和使用
1. 引言 合理利用线程池能够带来三个好处. 第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗. 第二:提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行. 第 ...
- window.jQuery || document...
window是浏览器端的全部数据变量的引用.比如 window.window === window window.jQuery 就是浏览器中的全局变量里的jQuery那为什么不写 jQuery 而是写 ...
- Mybatis动态公用sql
<select id="collPageCount" parameterType="java.util.Map" resultType="lon ...
- hdu 2844 Coins【多重背包】
题目链接:https://vjudge.net/contest/228640#problem/F 转载于:http://www.voidcn.com/article/p-mxcorksq-gh.htm ...
- Linux shell中处理
awk是行处理器: 相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题,通常用来格式化文本信息 awk处理过程: 依次对每一行进行处理,然后输出 awk命令形式: awk ...