Android JNI 中文字符传递
JNI使用时,需要传递中文,遇到乱码问题,多次尝试失败。遂仔细研究了下编码格式。
首先,需要明确几个关于字符编码的基本概念:
◆ java内部是使用的16bit的unicode编码(utf-16)来表示字符串的,无论英文还是中文都是2字节;
◆ jni内部是使用utf-8编码来表示字符串的,utf-8是变长编码的unicode,一般ascii字符是1字节,中文是3字节;
◆ c/c++使用的是原始数据,ascii就是一个字节,中文一般是GB2312编码,用2个字节表示一个汉字。
C语言中的汉字传递到java端
先来实现C语言中的汉字传递到java端,有两种方案:
- 1,在C端以字节传送到java端,在java中转换;
- 2,在C端就转换好。
下面来详细说明:
1,在C端以字节传送到java端,在java中转换编码格式;
在C中,将char*转换为jbyteArray,然后设置数据:
jbyteArray byteArray = env->NewByteArray(strlen(str));
env->SetByteArrayRegion(byteArray,0,strlen(str),(jbyte *)str);
在Java端,获取数组,然后从”gb2312”格式生成utf16格式的java字符串:
byte[] byteArray = JniClient.getChineseByteArray();
strSayHello = new String(byteArray,"gb2312");
2,在C端就转换好编码格式
步骤要复杂一些,核心还是一样的,是在C端通过jni访问java的String创建方法,进行编码格式转换。
jstring CStr2Jstring(JNIEnv* env, char* buf)
{jclass Class_string;jmethodID mid_String, mid_getBytes;jbyteArray bytes;jbyte* log_utf8;jstring codetype, jstr;Class_string = env->FindClass( "java/lang/String"); //获取class//先将gbk字符串转为java里的string格式mid_String = env->GetMethodID( Class_string, "<init>","([BLjava/lang/String;)V");int len=strlen(buf)+1;//需要加1,把字符串的结束符也包含进来bytes = env->NewByteArray( len);env->SetByteArrayRegion( bytes, 0, len, (jbyte*) buf);codetype = env->NewStringUTF( "gbk");jstr = (jstring)env->NewObject( Class_string, mid_String, bytes, codetype);env->DeleteLocalRef( bytes);//再将string变utf-8字符串。mid_getBytes = env->GetMethodID( Class_string, "getBytes", "(Ljava/lang/String;)[B");codetype = env->NewStringUTF( "utf-8");bytes = (jbyteArray)env->CallObjectMethod( jstr, mid_getBytes, codetype);log_utf8 = env->GetByteArrayElements( bytes, JNI_FALSE);return env->NewStringUTF((char *)log_utf8);
}
java中的汉字传递到C端
下面来实现java中的汉字传递到C端,也是两种方案:
- 1,在Java端就转换好编码格式。
- 2,java端只传递,在C端转换;
下面来详细说明:
1,在Java端就转换好编码格式
在Java中,将String转换为”gbk”格式的byte[]:
String strToJNI = "欢迎";
byte[] byteArr = new byte[strToJNI.length()*2];
byteArr=strToJNI.getBytes("gbk");
在C中,获取jbyteArray的起始地址,当成char*的地址访问即可:
jbyte * byteArr=env->GetByteArrayElements(byteArray,0);
char * buf = (char *)byteArr;
2,java端只传递,在C端转换;
在C语言中做编码格式的转换,步骤要复杂一些,但是核心思想还是一样的,就是在C端通过jni访问java的String创建方法,进行编码格式转换。
char* Jstring2CStr(JNIEnv* env, jstring jstr)
{char* rtn = NULL;jclass clsstring = env->FindClass("java/lang/String");//寻找 java里面String.classjstring strencode = env->NewStringUTF("GB2312");//创建java字符串 "gb2312"jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");//寻找到java String getbytes();jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr,mid,strencode); // String .getByte("GB2312");jsize alen = env->GetArrayLength(barr); //获取长度jbyte* ba = env->GetByteArrayElements(barr,JNI_FALSE); //jbyteArray转为jbyte*if(alen > 0){rtn = (char*)malloc(alen+1); //"\0"memcpy(rtn,ba,alen);rtn[alen]=0;}env->ReleaseByteArrayElements(barr,ba,0); //释放掉return rtn;
}
总结
1,优先选择在java端做字符编码格式的转换
通过上面的介绍,我们可以看出,在Java端实现编码格式的转换,代码更简洁,也更易于理解。所以,我们应该优先选择在java端做字符编码格式的转换。
2,C中字符串的长度
在C中向外传递时需要加1,将结束符传递出来(见CStr2Jstring())。否则,后面不知道会跟着什么随机数据的。
在java向C传递的byte数组,逐字节打印数组内容,数组的长度不能使用strlen(buf)(见SetChineseByteArray())。
传递的是byte数组,而不是字符串,所以这个长度不能使用strlen,而是需要调用env->GetArrayLength(byteArray)来获取。
3,C中的char类型
在C语言中调用日志打印函数,中文打印为乱码。
我是通过打印具体字节数据来验证传递成功的。
打印语句如下:
LOGI( "log: buf[%d]=%d",i,*(signed char *)(buf+i));
为何要强制转换为 signed char 呢?
我之前未使用强制转换时,打印出来的数据,并不一致,如下:
06-26 16:35:50.220: I/Hello(4529): log: byteArr[0]=-60
06-26 16:35:50.220: I/logfromc(4529): log: buf[0]=196
这两个数据有差异的原因在于:java中的byte,取值范围为[-128,127]。
在ARM平台上,C语言中的char的取值范围[0,255],也就是说,arm上的char是无符号的。通过计算:-60=196-256,可以知道值是匹配的。但是这样靠人脑计算比较累,所以就让电脑干啦(强制转换成 signed char)。
通常我们的手机的cpu都是ARM,例如我的手机就是arm啦,所以用char类型打印出来的值是不同的。
在模拟器上测试,C语言中的char是有符号的,取值范围[-128,127],因为模拟器是在PC上跑的,PC是x86平台。
char是有点特殊的啦,在不同平台上编译出来的情况,有所不同,可要注意哦。
demo下载:
http://download.csdn.net/detail/lintax/9560249
Android JNI 中文字符传递相关推荐
- android java调用参数,如何从命令行调用Android JNI函数并传递Java对象参数
一.前言 当我们对某个使用原生库(native library)的恶意软件或者应用进行分析或渗透测试时,如果能够对库函数进行隔离和执行是再好不过的事情,这样做我们就可以使用其自身的代码来调试对抗恶意软 ...
- jni 传递字符串到java_Android JNI开发-java与c++其间的中文字符串传递
Android JNI开发---java与c++之间的中文字符串传递 最近在做一个Android电子词典,其中在从词库中读取词条时,用到了jni---java调用c++;在java代码里调用本地方法时 ...
- 网页编码与数据传递中的中文字符编码
最近工作中遇到中文编码,中文参数传递,AJAX返回值包含中文乱码的问题,为此奋斗了一宿,有点心得,有点体会,总结如下,希望对迷惑于此中者有解惑之功效! 在网上一阵狠搜,编码函数的确是有,包括Javas ...
- android 4.4.3上面,联系人的头像默认显示首字母,但是不支持中文字符,修改支持中文
在android 4.4.3上面,联系人的头像默认显示首字母,但是不支持中文字符,如下图: 如果联系人名字的第一位是英文字符(a-z || A-Z),则默认头像将显示该首字母. 如果支持中文时显示第一 ...
- android 判断是否是标点符号_Java 中文字符判断 中文标点符号判断
Java Character 实现Unicode字符集介绍 CJK中文字符和中文标点判断 主要内容: 1. Java Character类介绍: 2. Unicode 简介及 UnicodeBloc ...
- android怎样判断中文字符,android 判断字符串中英文
// 判断一个 char 是否是中文字符(CJK 分别代表中文.日文.韩文) public static boolean isChinese(char c) { Character.UnicodeBl ...
- android jni jstring 转 char*
今天,简单讲讲Android jni如何将java的Sring转成char*. 这个之前一直不理解,所以我都是android传入byte[]转成char*,有一篇博客专门讲了这个.后来发现用Strin ...
- Android JNI学习(四)——JNI的常用方法的API
前三篇主要讲解了jni基础相关的理论知识,今天主要讲解一下JNI的常用方法的API,掌握了基本的理论知识和常用的API接下来才能更好的实战. jni的常用API大纲 再看API前,我建议大家主要结合官 ...
- android post json格式,Android中post请求传递json数据给服务端的实例
在最近的项目中有个需求是这样的: 入参封装成JSON,EXAMPLE: { "uuid": "iamauuid","clientType": ...
最新文章
- php+微信开发+解绑,微信开发之解绑设备通知的方法
- 通过 Visual Studio 的“代码度量值”来改进代码质量
- 无限序列 (ybtoj C.3)
- 基于linux环境采用update-alternatives 方式进行python版本切换
- 揭秘大流量场景下发布如「丝般顺滑」背后的原因
- Aliyun Serverless VSCode Extension 上架并开源
- ajax 异步插入图片到数据库(多图上传)
- tar包在linux下 java安装
- 开始研究WEKA,一个开源java的数据挖掘工具
- Socket编程之TCP实例(附C/C++代码详解)
- 垃圾代码评析——关于《C程序设计伴侣》9.4——链表(一)
- warning: mysql-community-libs-5.7.11-1.el7.x86_64.rpm: Header V3 DSA/SHA1 Signature, key ID 5072e1f5
- SQLServer数据库基础教程
- 如何写出一份好的解决方案
- Java是什么?Java到底能干嘛?
- 银行卡四要素验证补充测试
- MATLAB 线性拟合
- matplotlib交互式数据光标实现——mplcursors
- 华为P30销量破千万有多少含金量?
- 利用python分析电商_Python电商数据分析实战
热门文章
- 启用计算机的无线同屏,完美:将计算机转换为无线显示器,Windows 10的此功能确实强大...
- 解决win10笔记本内置麦克风不能用的历程和方法
- PID控制------伯德图原理
- TSN(temporal segment networks)环境配置
- 晶体三极管的结构和符号
- 用于大数据的星际文件系统
- c语言程序设计教程南京大学出版社答案,《新编C语言程序设计教程》习题解答与实验指导...
- 基于单片机定时闹钟设计
- MT8516处理器简介—MT8516芯片技术资料解析
- 关于Wrap Lighting与皮肤SSS