因为项目编码中通过JNI传递中文字符时出现乱码问题,特搜集了相关资料,整理如下:
java内部是使用16bit的unicode编码(UTF-16)来表示字符串的,无论中文英文都是2字节;
jni内部是使用UTF-8编码来表示字符串的,UTF-8是变长编码的unicode,一般ascii字符是1字节,中文是3字节;
c/c++使用的是原始数据,ascii就是一个字节了,中文一般是GB2312编码,用两个字节来表示一个汉字。
1、java --> c/c++
这种情况中,java调用的时候使用的是UTF-16编码的字符串,jvm把这个字符串传给jni,c/c++得到的输入是jstring,这个时候,可以利用jni提供的两种函数,一个是GetStringUTFChars,这个函数将得到一个UTF-8编码的字符串;另一个是GetStringChars这个将得到UTF-16编码的字符串。无论那个函数,得到的字符串如果含有中文,都需要进一步转化成GB2312的编码。
在C++编写的DLL文件中添加如下转换函数:
char * JStringToCharArray(JNIEnv * pJNIEnv, jstring jstr)
{
jsize len = pJNIEnv->GetStringLength( jstr );
const jchar * jcstr = pJNIEnv->GetStringChars( jstr, NULL );
int size = 0;
char * str = ( char * )malloc( len * 2 + 1 );
if ( (size = WideCharToMultiByte( CP_ACP, 0, LPCWSTR( jcstr ), len, str, len * 2 + 1, NULL, NULL ) ) == 0 )
return NULL;
pJNIEnv->ReleaseStringChars( jstr, jcstr );
str[ size ] = 0;
return str;
}
假设DLL中以下这个函数接受到JAVA传递的带有中文的字符串jMsg,处理如下:
JNIEXPORT void JNICALL Java_Test_hello(JNIEnv * env, jclass obj, jstring jMsg)
{
//若使用const char *strMsgPtr = env->GetStringUTFChars( jMsg , 0)则会出错
char * strMsgPtr = JStringToCharArray( env, jMsg ); //使用上面提供的转换函数接收字符串
/*
接下来便可使用strMsgPtr做你所需要的处理
*/
}
2、c/c++ --> java
jni返回给java的字符串,c/c++首先应该负责把这个字符串变成UTF-8或者UTF-16格式,然后通过NewStringUTF或者NewString来把它封装成jstring,返回给java就可以了。
如果字符串中不含中文字符,只是标准的ascii码,那么用GetStringUTFChars/NewStringUTF就可以搞定了,因为这种情况下,UTF-8编码和ascii编码是一致的,不需要转
但是如果字符串中有中文字符,那么在c/c++部分进行编码转换就是一个必须了。
转载自: http://hi.baidu.com/ivy_jing/blog/item/1a2d90899712f119c8fc7a29.html
阅读(5453) | 评论(0) | 转发(0) |