简述

有一个需求是这样的,写的一个程序内置了一个很大的文件(实际就是抓取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缩小程序体积的更多相关文章

  1. 减小Delphi XE5编译出来的程序体积

    默认Delphi XE, XE2, XE3,XE4,XE5, XE6 ... 编译出来的程序体积很大. 一般用两个方法可以很大程度上减少程序体积. 一.在工程中用编译指令禁用RTTI 禁用的方法很简单 ...

  2. 黄聪:优化清理WordPress数据库wp_options表(缩小autoload体积)

    使得wp_options表变得庞大的重要原因:无用的RSS Feed Cache.如果你在wp_options表中发现了大量option_name包含“_transient”的数据,那就是它没跑了.先 ...

  3. 如何为你的微信小程序体积瘦身?

    众所周知,微信小程序在发布的时候,对提交的代码有1M大小的限制!所以,如果你正在写一个功能稍微复杂一点的小程序,就必须得时刻小心注意你的代码是不是快触及这个底线了. 在设计一个小程序之初,我们就需要重 ...

  4. 使用--gc-section编译选项减小程序体积

    本周在给程序添加功能的时候,突然发现,我只是写了几个函数,还没调用,size就变大了.这肯定是不行的嘛,没用的函数就应该不链接进来,占用我宝贵的空间. 这种功能,讲道理编译器肯定要支持的,于是搜了一下 ...

  5. 缩小jquery体积

    jQuery 分析 据统计,目前全世界57.3%的网站使用它.也就是说,10个网站里面,有6个使用jQuery.如果只考察使用工具库的网站,这个比例就会上升到惊人的91.7%. 虽然jQuery如此受 ...

  6. 使用模块化编译缩小 apk 体积

    libcocos2dlua.so编译出来有11M多,其中包含了很多不需要的模块,模块化编译,把不需要用到的模块弄成0,体积就小了. 如: 修改D:\codeide\sDiShu2formm\frame ...

  7. VC++下编译 程序“减肥”

    在vc6 和 vs 2008下 编译 以下代码,不更改任何编译设置(vc6  40k , s2008 7k). 一.vc6下,Release 模式 编译处理. 1.去掉不必要的 链接库  工程(Pro ...

  8. 安全之路 —— 使用Windows全局钩子打造键盘记录器

    简介 键盘记录功能一直是木马等恶意软件窥探用户隐私的标配,那么这个功能是怎么实现的呢?在Ring3级下,微软就为我们内置了一个Hook窗口消息的API,也就是SetWindowsHookEx函数,这个 ...

  9. 使用Windows全局钩子打造键盘记录器

    简介 键盘记录功能一直是木马等恶意软件窥探用户隐私的标配,那么这个功能是怎么实现的呢?在Ring3级下,微软就为我们内置了一个Hook窗口消息的API,也就是SetWindowsHookEx函数,这个 ...

随机推荐

  1. 【C++ Primer | 15】C++虚函数表剖析②

    多重继承 下面,再让我们来看看多重继承中的情况,假设有下面这样一个类的继承关系. 注意:子类只overwrite了父类的f()函数,而还有一个是自己的函数(我们这样做的目的是为了用g1()作为一个标记 ...

  2. 浅谈Spring MVC知识

    关于MVC框架,我相信大家都不陌生,都会说也就是模型-视图-控制器这三层的框架结构,如果你参加面试的时候考官会问:“MVC框架是什么?你说一说.”其实我们都知道这个问题还需要问的,只要你是一个开发人员 ...

  3. 天天爱跑步&&弹球

    题解: 弹球题目地址:https://www.nowcoder.com/acm/contest/113/E 后面这题 应该是天天爱跑步的加强版本 原理都是查询子树中dep[x]+f[x]的值的个数 由 ...

  4. 记录weiye项目上线遇到的一些问题

    1.使用vpn访问客户内网 参考:http://jingyan.baidu.com/article/a3f121e4f9903cfc9052bb0b.html 2.设置使用ip地址直接访问项目(之后可 ...

  5. 024 SpringMvc的异常处理

    一:说明 1.介绍 Springmvc提供HandlerExceptionResolver处理异常,包括Handler映射,数据绑定,以及目标方法执行. 2.几个接口的实现类 AnnotationMe ...

  6. codeforces 366C Dima and Salad 【限制性01背包】

    <题目链接> 题目大意: 在一个水果篮里有n种水果,并且这些水果每一种都有一个美味度和一个卡路里的属性, 小明要从这些水果中选出来一些做一个水果沙拉, 并且要求他的水果沙拉的美味度是卡路里 ...

  7. 计蒜客 淘宝的推荐系统【DP】

    题目链接:https://nanti.jisuanke.com/t/26984                                                             ...

  8. MySQL数据库基本用法

    远程连接数据库 mysql -u root -p #-u 用户名 -h后面写要连接的主机ip地址 -u后面写连接的用户名 -p回车后写密码 回车后输入密码,当前设置的密码为toor 数据库操作 创建数 ...

  9. mvc返回多个结果集,返回多个视图

    System.Web.Mvc.ViewPage<dynamic> public ActionResult Index()     {             IDictionary< ...

  10. CF 633 F. The Chocolate Spree 树形dp

    题目链接 CF 633 F. The Chocolate Spree 题解 维护子数答案 子数直径 子数最远点 单子数最长直径 (最长的 最远点+一条链) 讨论转移 代码 #include<ve ...