Android开发论使用Java层的Zlib压缩和使用C底层的Zlib压缩的对比

来源:互联网 发布:网络推广视频 编辑:程序博客网 时间:2024/05/17 21:42

开头说下,Java层的Zlib压缩源码地址:https://github.com/ymnk/jzlib

  C底层的Zlib压缩源码地址:http://www.zlib.net/


Java层的是纯的java上层语言实现,C底层的肯定都是C语言实现的了。

项目中有需求,需要将请求的数据封装成json字符串上传,并且需要对json字符串先做Zlib的数据压缩,再AES加密,最后再Base64下;听起来这是一般的做法,没啥大问题,但是,我们项目中有需要上传图片的操作,而且上传图片不是使用的文件形式上传,而是获取图片的数据流然后转化成String字符串封装到刚才说到的json中上传。对于图片的上传而且不怎么限制大小,默认超过3MB的图片才压缩,但是3MB的图片转化成byte数组那也是很大的,上传没啥问题,但是在实际操作中,发现上传一张2MB左右的图片会很慢,基本2分钟左右才会上传成功,自己就打断点,看下到底那步耗费了时间,最后在内容加密的过程中有2分钟的等待,继续进入,发现最终的耗费时间点是在Zlib压缩的时候,详细看了下压缩的具体操作,第一次用的是Java层的Zlib库压缩的,在压缩的时候需要创建一个byte数组,也就是压缩过程中的缓冲区吧,而这个缓冲区的大小是图片byte数组的2倍再加一个比如1024*100的数值,看这里就已经很大了,如果内部再有循环遍历的操作,那计算量没法估量了,至此已经找到了问题所在,首先的解决办法就是尝试下用C语言的Zlib库试试。


1.去官网下载Zlib库的源码,然后导入eclipse中进行编译操作,因为在AS中我不知道怎么配置Cmake,暂时就用eclipse编译吧

2.创建jni目录,目录中包含zlib-1.2.11目录,创建Android.mk文件,创建mytest.c文件

3.jni目录下的Android.mk内容如下

LOCAL_PATH:= $(call my-dir)    include $(CLEAR_VARS)    include $(CLEAR_VARS)    LOCAL_SRC_FILES := mytest.c  LOCAL_C_INCLUDES :=$(LOCAL_PATH) $(LOCAL_PATH)/..    LOCAL_STATIC_LIBRARIES := libzlib  LOCAL_MODULE := libmyzlib    include $(BUILD_SHARED_LIBRARY)    include $(call all-makefiles-under,$(LOCAL_PATH))  

4.mytest.c目录如下

#include <jni.h>#include "zlib.h"#include <string.h>jstring chartojstring( JNIEnv* env, const char* pat){    /*jclass strClass = (*env)->FindClass(env,"java/lang/String;");    jmethodID ctorID = (*env)->GetMethodID(env,strClass, "<init>", "([BLjava/lang/String;)V");    jbyteArray bytes = (*env)->NewByteArray(env, strlen(pat));    (*env)->SetByteArrayRegion(env,bytes, 0, strlen(pat), (jbyte*)pat);    jstring encoding = (*env)->NewStringUTF(env,"utf-8");    return (jstring)(*env)->NewObject(env,strClass, ctorID, bytes, encoding);    */    /*    jstring stoJstring(JNIEnv* env, const char* pat){       jclass strClass = env->FindClass("Ljava/lang/String;");       jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");       jbyteArray bytes = env->NewByteArray(strlen(pat));       env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);       jstring encoding = env->NewStringUTF("utf-8");       return (jstring)env->NewObject(strClass, ctorID, bytes, encoding);}    */    return (*env) -> NewStringUTF(env, pat);}char* jstringTostring(JNIEnv* env, jstring jstr){       char* rtn = NULL;       jclass clsstring = (*env)->FindClass(env, "java/lang/String");       jstring strencode = (*env)->NewStringUTF(env, "utf-8");       jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes", "(Ljava/lang/String;)[B");       jbyteArray barr= (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid, strencode);       jsize alen = (*env)->GetArrayLength(env, barr);       jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE);       if (alen > 0)       {                 rtn = (char*)malloc(alen + 1);                 memcpy(rtn, ba, alen);                 rtn[alen] = 0;       }       (*env)->ReleaseByteArrayElements(env, barr, ba, 0);       return rtn;}jbyteArray Java_com_zhianyi_protopia_util_encryp_AESUtil_compressStr(JNIEnv* env, jobject thiz, jstring str,jint len){    char* strSrc = jstringTostring(env, str);    int lenght = len;    Byte *buff=(Byte *)malloc(lenght*sizeof(Byte *));    if(!buff){    memcpy(buff, "mem_error", strlen("mem_error")+1);    }    unsigned long bufLen = lenght;    int ret = compress(buff, &bufLen, strSrc, strlen(strSrc) + 1);    if (Z_OK != ret)    {        memcpy(buff, "error", strlen("error")+1 );    }    jbyteArray retArray = (*env)->NewByteArray(env, bufLen);    (*env)->SetByteArrayRegion(env, retArray, 0, bufLen, buff);    free(buff);    return retArray;}jstring Java_com_zhianyi_protopia_util_encryp_AESUtil_uncompressStr(JNIEnv* env, jobject thiz, jbyteArray bArray,jint len){    jsize length = (*env)->GetArrayLength(env, bArray);    jbyte* pArrayByte = (*env)->GetByteArrayElements(env, bArray, 0);    int ll = len;    unsigned char *buff=(unsigned char *)malloc(ll*sizeof(unsigned char *));    if(!buff){       memcpy(buff, "mem_error", strlen("mem_error")+1);    }    unsigned long bufLen = ll;    int ret = uncompress(buff, &bufLen, pArrayByte, length);/*    if (Z_OK != ret)    {        memcpy(buff, "error", strlen("error")+1);    }*/    if (Z_DATA_ERROR == ret)    {        memcpy(buff, "data_error", strlen("data_error")+1);    }    if (Z_BUF_ERROR == ret)    {        memcpy(buff, "buf_error", strlen("buf_error")+1);    }    if (Z_MEM_ERROR == ret)    {        memcpy(buff, "mem_error", strlen("mem_error")+1);    }    jstring str = chartojstring(env, buff);    free(buff);    return str;}jstring Java_com_zhianyi_protopia_util_encryp_AESUtil_getVersion(JNIEnv* env, jobject thiz){    const char* version= zlibVersion();    return chartojstring(env, version);}
这段代码是网上找的,但是解压压缩少的内容没事,压缩解压大的就会报buff_error就是缓冲区异常,就是小了,所以将缓冲区的大小修改为外部传入的大小,解决。
5.在zlib-1.2.11目录下创建Android.mk文件,内容如下
LOCAL_PATH:= $(call my-dir)    APP_ABI := ALL  include $(CLEAR_VARS)    LOCAL_SRC_FILES := adler32.c compress.c crc32.c deflate.c gzclose.c gzread.c gzwrite.c infback.c inffast.c inflate.c inftrees.c trees.c uncompr.c zutil.c    LOCAL_MODULE:= libzlib    include $(BUILD_STATIC_LIBRARY)  


以上代码也是网上找的,但是他是基于低版本的,把LOCAL_SRC_FILES该项的文件填上所有的.c文件就好,我们用到的就这些,所以有些没用到的可以不用编译。

6.然后就是在cmd环境下使用ndk-build命令来编译了。

在命令行输入ndk-build就可以编译成功了,但是默认只编译了armeabi

使用ndk-build APP_ABI="all"就是全平台的so文件了。

至此编译工作OK了,然后就是导入工程使用了,


7.因为我是在AS中开发的,所以需要导入AS中开发使用,至于AS中怎么导入网上百度吧。



0 0
原创粉丝点击