jni中字符转换中文乱码的处理方法

转自: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                  vwchar_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         |NewStringUTFwchar_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 );
  char* rtn = (char*)malloc( length*2+1 );
  int size = 0;
  size = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)jcstr, length, rtn,(length*2+1), 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;
}

时间: 2024-10-06 00:29:33

jni中字符转换中文乱码的处理方法的相关文章

Linux中vi显示中文乱码的问题

由于在windows下默认是gb编码,而我的vim默认是utf-8(gedit默认也是utf-8),所以打开会成乱码.修改了一下配置文件,使vi支持gb编码就好了.$vi ~/.vimrclet &termencoding=&encodingset fileencodings=utf-8,gbk$:wq再次打开vi,显示就正常了.vim中编辑不同编码的文件时需要注意的一些地方此文讲解的是vim编辑多字节编码文档(中文)所要了解的一些基础知识,注意其没有涉及gvim,纯指字符终端下的vim.

关于perl中,中文乱码的解决方法

今天在测试自己写的邮件模块的时候,发现客户端收到的邮件标题是乱码,于是学习了一下perl中对字符串处理的机制,再次记录下,也希望以后对其他朋友有所帮助 首先perl只能处理2种编码的格式,ascii码和utf-8. 那么perl首先要确定一个字符串是octets还是utf8编码,他完全是靠字符串上的utf8 flag. 在perl内部,字符串结构由两部分组成: [utf8 + 数据].如果utf8 flag是on的话, perl就会把它当成utf8字符串来处理, 如果utf8 flag为off,

IDEA中 tomcat 控制台中文乱码解决 及GsonUtils无法转换时间格式

IDEA中 tomcat 控制台中文乱码解决 1.找到tomcat 安装目录下的 conf /logging.properties 文件打开 2.将 java.util.logging.ConsoleHandler.encoding = UTF-8 修改为 java.util.logging.ConsoleHandler.encoding = GBK 3.保存后 重启idea ————————————————GsonUtils需添加时间模式 datePattern指定模式 原文地址:https:

Java中Servlet输出中文乱码问题

1.现象:字节流向浏览器输出中文,可能会乱码(IE低版本) private void byteMethod(HttpServletResponse response) throws IOException, UnsupportedEncodingException { String date = "你好"; ServletOutputStream outputStream = response.getOutputStream(); outputStream.write(date.get

SSH Secure Shell Client中文乱码的解决方法

这是SSH Secure Shell Client多年未解决的短板,要求客户端和服务器端都要'UTF-8'编码,Windows中文版的编码是非UTF-8.zh_CN.UTF-8是UTF编码的中文语言环境.Windows使用的是GB2312编码,大多数linux系统支持的是UTF-8编码,而远程登陆时使用的是本地编码,所以会出现乱码的问题:现有几种解决方案: 方案一:修改linux服务器的环境变量 使用linux,在用户根目录下有一个.bash_profile配置文件,该配置只对当前用户有效.若对

C. PHP读取TXT中文乱码的解决方法

PHP读取TXT中文乱码的解决方法 2013-03-01 19:12 2203人阅读 评论(0) 收藏 举报 //$fname文件名称 if ($fname = $_FILES['nickname']['tmp_name']) { //file_get_contents() 函数把整个文件读入一个字符串中. $contents = file_get_contents($fname); //获取文件的编码方式 $encoding = mb_detect_encoding($contents, ar

Sublime Text 3打开txt中文乱码的解决方法

Sublime Text是一个非常强大的编辑器,可是对中文的支持并不好,在Sublime Text 2 时,可以通过命令行的方式安装编码包来解决,但Sublime Text 3不能通过这样的方式解决 在安装完Sublime Text 3后要下载一个ConvertToUTF8包放到C:\Users\用户名\AppData\Roaming\Sublime Text 3\Packages(安装目录可能不是这个,但可以在sublime中preference - browse packages打开此目录)

Visual Assist X在Windows 8.1下出现中文乱码的解决方法

这主要是输入法造成的,我的输入法中有US.中文.搜狗输入法三个输入法:通过搜狗输入法管理器把"中文"去掉,或者通过语言首选项把"中文"去掉就不会在出现乱码. 这个办法的思路来自于http://www.cnblogs.com/Coling/p/3527233.html,但他说的是把除搜狗之外的都删除,我不赞同,作为开发者,经常输入英文,且经常使用Shift,只保留搜狗,那写代码时要累死.于是尝试删除"中文",结果就搞定了. Visual Assis

提交数据的中文乱码的解决方法

使用GET方式提交数据的中文乱码的解决方法: 使用URLEncoder.encode(name,"UTF-8")进行url编码:      String path = "http://192.168.22.136:8080/web/servlet/LoginServlet?username="+URLEncoder.encode(name,"UTF-8")+"&password="+URLEncoder.encode(