在JNI调用C实现的本地方法时,我们曾经介绍过直接修改控制台代码页的方式解决中文乱码问题(文章参见:http://wiki.xuetang9.com/?p=5254 ),但是到了C++实现,这个方法又不管用了,折腾了一个下午,终于找到了解决问题的方法,分享如下:
1、相关概念
大家都知道,Java内部采用的是16位Unicode编码来表示字符串,中英文都采用2字节;而JNI内部是使用UTF-8编码来表示字符串,UTF-8编码其实就是Unicode编码的一个变长版本(对应关系参见文章:http://wiki.xuetang9.com/?p=5207 ),一般的ASCII字符占1个字节,中文汉字是3个字节;
C/C++使用的是原始数据,ASCII字符就是一个字节,中文一般是GB2312编码,使用两个字节表示一个中文字符。
明确了概念,操作就比较清楚了。下面根据字符流的方向来分别说明一下:
1-1:从Java 到 C/C++
这种情况下,Java调用的时候使用的是UTF-16编码的字符串,JVM把这个字符串传给JNI,C/C++得到的输入是jstring,这个时候,可以利用JNI提供的两种函数,一个是GetStringUTFChars,这个函数将得到一个UTF-8编码的字符串;另一个是 GetStringChars这个将得到UTF-16编码的字符串。无论哪个函数,得到的字符串如果含有中文,都需要进一步转化成GB2312的编码。示意图如下:
1-2:从C/C++ 到 Java
从JNI返回给Java的字符串,C/C++首先就会负责把字符串转换为UTF-8或UTF-16的格式,然后通过NewStringUTF()或NewString()方法将字符串封装成jstring,返回给Java就可以了:
如果字符串中不含中文字符,只是标准ASCII码,使用GetStringUTFChars()/NewStringUTF()方法就可以搞定了,因为这个情况下,UTF-8编码和ASCII编码是一致的,不需要转换。
但是如果字符串中存在中文字符,那么就必须在C/C++程序中进行转码操作。这里要说明一下:Linux和Win32都支持wchar,这个实际上就是宽度为16位的Unicode编码UTF-16。所以,如果我们的C/C++程序中完全使用wchar类型,理论上就不需要这种硬转换了。但是实际上,大家在写程序的时候不可能完全用wchar来取代char,所以就目前大多数应用而言,转换仍然是必须的。
2、转换方法
需要包含的头文件:
#include<stdio.h>#include<stdlib.h>#include<malloc.h>#include<memory.h>#include<Windows.h>
使用wide char 类型来做转换:
/**
* 将Java传来的UTF8/16编码转换为C/C++能够正常显示的GB2312编码
*/char*jstringToWindows(JNIEnv*env,jstring jstr){intlength=(env)->GetStringLength(jstr);constjchar*jcstr=(env)->GetStringChars(jstr,0);char*rtn=(char*)malloc(length*2+1);intsize=0;size=WideCharToMultiByte(CP_ACP,0,(LPCWSTR)jcstr,length,rtn,(length*2+1),NULL,NULL);if(size<=0)returnNULL;(env)->ReleaseStringChars(jstr,jcstr);rtn[size]=0;returnrtn;}
/**
* 将C/C++中的GB2312编码转换成UTF8/16编码
*/jstringWindowsTojstring(JNIEnv*env,constchar*str){jstring rtn=0;intslen=strlen(str);unsignedshort*buffer=0;if(slen==0){rtn=(env)->NewStringUTF(str);}else{intlength=MultiByteToWideChar(CP_ACP,0,(LPCSTR)str,slen,NULL,0);buffer=(unsignedshort*)malloc(length*2+1);if(MultiByteToWideChar(CP_ACP,0,(LPCSTR)str,slen,(LPWSTR)buffer,length)>0)rtn=(env)->NewString((jchar*)buffer,length);}if(buffer)free(buffer);returnrtn;}
老九学堂出品,转载请私信哦
对于文章内容有不理解的可以添加老九君个人QQ:614940318,请备注来自简书
老九学堂免费C、C++、Java课程地址:
https://study.163.com/courses-search?keyword=%E8%80%81%E4%B9%9D%E5%AD%A6%E5%A0%82
网友评论