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

开头说下,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中怎么导入网上百度吧。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值