转自:http://blog.sina.com.cn/fangaosjtu
这两天在学习使用jni,在java程序中,调用海量词典的dll。利用jni的GetStringChars函数和NewString函数时,遇到了中文乱码的问题,折腾了一个晚上。查阅了一些资料,总结如下:
一.相关概念
- 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的编码。示意图如下:
String
(UTF-16)
|
[java] |
-------------------- JNI 调用
[cpp] |
v
jstring
(UTF-16)
|
+--------+---------+
|GetStringChars |GetStringUTFChars
| |
v v
wchar_t* char*
(UTF_16) (UTF-8)
2、c/c++ --> java
jni返回给java的字符串,c/c++首先应该负责把这个字符串变成UTF-8或者UTF-16格式,然后通过NewStringUTF或者NewString来把它封装成jstring,返回给java就可以了。
String
(UTF-16)
^
|
[java] |
-------------------- JNI 返回
[cpp] |
jstring
(UTF-16)
^
|
+--------+---------+
^ ^
| |
|NewString |NewStringUTF
wchar_t* char*
(UTF_16) (UTF-8)
如果字符串中不含中文字符,只是标准的ascii码,那么使用GetStringUTFChars/NewStringUTF就可以搞定了,因为这种情况下,UTF-8编码和ascii编码是一致的,不需要转换。
但是如果字符串中有中文字符,那么在c/c++部分进行编码转换就是一个必须了。我们需要两个转换函数,一个是把UTF8/16的编码转成GB2312;一个是把GB2312转成UTF8/16。
这里要说明一下:linux和win32都支持wchar,这个事实上就是宽度为16bit的unicode编码UTF16,所以,如果我们的 c/c++程序中完全使用wchar类型,那么理论上是不需要这种转换的。但是实际上,我们不可能完全用wchar来取代char的,所以就目前大多数应 用而言,转换仍然是必须的。
二。一种转换方法
使用wide char类型来转换。
char* jstringToWindows( JNIEnv *env, jstring jstr )
{ //UTF8/16转换成gb2312
int length = (env)->GetStringLength(jstr );
const jchar* jcstr = (env)->GetStringChars(jstr, 0 );
int clen = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)jcstr, length, NULL,0, NULL, NULL );
char* rtn = (char*)malloc( clen ) //更正。作者原来用的是(char*)malloc( length*2+1 ),当java字符串中同时包含汉字和英文字母时,所需缓冲区大小并不是2倍关系。
int size = 0;
size = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)jcstr, length, rtn,clen, NULL, NULL );
if( size <= 0 )
return NULL;
(env)->ReleaseStringChars(jstr, jcstr );
rtn[size] = 0;
return rtn;
}
jstring WindowsTojstring( JNIEnv* env, const char* str )
{//gb2312转换成utf8/16
jstring rtn = 0;
int slen = strlen(str);
unsigned short * buffer = 0;
if( slen == 0 )
rtn = (env)->NewStringUTF(str );
else
{
int length = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, NULL, 0 );
buffer = (unsigned short *)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 );
return rtn;
}
相关推荐
接下来,我们讨论处理Java返回的中文字符串乱码的问题。这通常涉及到字符编码的转换。在JNI中,Java字符串通常是`jstring`类型,可以使用`env->GetStringUTFChars`获取UTF-8编码的字符数组。但是,如果你需要在C/C++...
在Android中,由于字符编码的问题,中文字符在JNI层间的传递可能会遇到问题,例如乱码。因此,理解和掌握正确的编码处理方式是至关重要的。 描述提到"实现了C语言与java端之间互相传递汉字的功能",这意味着这个...
2. `out.print(new String(test.getBytes(), "GBK"))`尝试将UTF-8编码的字符串转换为GBK,但由于原始字符串已经是UTF-8,转换后的结果每个中文字符通常会占用4到5个字节,导致C++解码失败。 3. `out.print(new ...
在处理中文乱码问题上,我们可以编写C/C++本地库,对输入的中文字符串进行加密,然后在Java中调用这个库进行解密。这样,即使中间环节出现编码问题,最终解密后的中文字符串也能正确恢复。 具体步骤如下: 1. **...
在`CharsetProcess`类中,`U2C`方法将UTF-8编码的Java字符串转换为GBK编码的字节数组,然后在C端直接处理GBK编码的数据。 总结来说,JNI处理汉字问题的关键在于理解编码之间的转换以及确保数据在Java和C/C++之间以...
标题 "lsn07_JNI获取String.zip" 涉及到的是JNI(Java Native Interface)技术,主要用于Java和C/C++之间的交互。...这个压缩包可能包含了示例代码、解释和步骤,帮助开发者更好地理解和实践JNI字符串操作。
最近遇到一个问题,把某个字符串计算MD5,之后把该字符串加密与MD5一起上传到服务端,服务端解密后重新计算md5发现与上传的MD5不一致,而出问题的字符串中无一例外都有Emoji表情。但我自己弄个带表情的字符串上传却...
在Java中,可以使用`Charset`类和`CharsetDecoder`来解码字符串。尝试使用常见的字符集,如UTF-8、ISO-8859-1等,直到找到能正确显示所有字符的那一个。 对于不兼容的MP3文件,可能需要使用第三方库,如`taglib`,...
- 字符串转换过程中需要注意编码问题,Java使用UTF-16编码,而C++可能使用ASCII或UTF-8编码,确保编码一致以避免乱码。 - 在多线程环境中,每个线程都有自己的`JNIEnv`指针,确保在正确的线程中执行这些操作。 在...
2. 在JNI方法中,使用`NewStringUTF()`函数创建一个UTF-8编码的Java字符串,而不是`NewByteArray()`,因为`NewStringUTF()`会自动处理从UTF-8到Java内部UTF-16的转换。 3. 检查身份证读卡器的SDK文档,确保使用正确...
在混合编程中,字符串处理是一个关键点,因为Java的字符串默认使用UTF-8编码,而在C++中可能需要进行编码转换以避免乱码问题。JNI提供了一些辅助函数,如`GetStringUTFChars`和`NewStringUTF`,用于在C++和Java之间...
native-audio,这里说明下Android中的JNI的中文乱码问题。 我们新建一个native.c的时候。eclipse对native.c默认的是GBK。我试着在java中把GBK转为UTF-8,依旧乱码,因此我也不知道jni返回的中文字符串是什么类型。
此外,确保Java程序也正确设置字符编码,避免在显示或处理字符串时出现乱码。 总的来说,二代身份证读卡器的二次开发涉及了多种技术,包括底层硬件通信、多语言间的交互以及字符编码的处理,需要对这些领域有深入的...
在转换完成后,再将处理过的字符串传递给JNI的`JNIEnv`接口,通过`NewByteArray`和`SetByteArrayRegion`设置Java字节数组。这样,Java端接收到的数据就能正确解码,避免出现乱码。 总结来说,二代身份证读卡器的二...
在处理中文字符时,由于ZPL本身并不直接支持中文,我们需要采用一些特殊的方法来实现。 首先,我们需要了解Java在处理这种问题时的角色。Java是一种多平台的、面向对象的编程语言,其强大的I/O功能使得我们可以方便...
Java串口操作是Java应用程序与外部设备通信的重要方式,...如果遇到乱码问题,可能需要检查串口配置是否与打印机手册中的参数一致,或者尝试使用不同的字符集。RXTX的灵活性和稳定性使其成为解决此类问题的理想选择。
- 在C++中,如果字符串处理不当,可能会导致乱码。例如,没有正确地指定字符集或者在读取身份证信息后没有进行正确的编码转换。 5. **解决乱码问题**: - 检查读卡器返回的身份证信息的编码格式,确保C++代码使用...
4. **字符串处理**:在处理用户输入或系统输出的字符串时,iconv可以帮助确保编码正确性,防止乱码出现。 **使用示例** 在Android中使用iconv库的一个简单示例是: ```java public class IconvExample { static ...
注意,C++的`szStr`变量可以正常传递中文字符串到Java,表明Java和C++之间的JNI通信基本正常。问题可能在于读取身份证信息的步骤。 为了解决乱码问题,你需要确保以下几点: - 确认身份证读卡器返回的数据编码格式...