这两天在学习使用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 );
  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;
}

 

补充(需要包含的头文件):

/*包含*/
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <Windows.h>

http://hi.baidu.com/menghaisheng/blog/item/33e19cfc5a237354d6887d07.html

中字符转换中文乱码的处理方法相关推荐

  1. RStudio控制台(console)中出现少量中文乱码的解决方法

    RStudio控制台(console)中出现少量中文乱码的解决方法 参考文章: (1)RStudio控制台(console)中出现少量中文乱码的解决方法 (2)https://www.cnblogs. ...

  2. c++中关于SQLite中文乱码的解决方法

    在使用SQLite的过程中(c++),如果创建一个表,如果SQL语句中包含中文字符,就会报错:如果是从数据库表中查询数据,如果数据库表中的某些字段为中文,查询结果也不能正常显示,出现这种情况的原因是因 ...

  3. ASP中 Request.Form中文乱码的解决方法

    分享下解决方法 直接用request.Form()获取的是所有数据所以会有乱码(具体原因不祥) 用 VBScript code Foreachobj in Request.Form Response. ...

  4. java 转换gbk编码,java中GBK转UTF-8乱码的解决方法

    java中GBK转UTF-8乱码的解决方法 如果自己采用的是GBK编码,对方采用得到是UTF-8编码,发送数据时需要将GBK编码数据转换成UTF-8编码数据,这样对方才不会乱码. 问题出现:GBK转U ...

  5. 【转】QT中使用MYSQL中文乱码解决方法

    [转]QT中使用MYSQL中文乱码解决方法 Linux下乱码解决办法: 1.在QT程序的main.cpp的main函数中添加红色字那三句: int main(int argc, char *argv[ ...

  6. ftl转PDF服务器上中文不显示,解决Linux中swftools转换中文pdf时出现乱码问题

    前段时间安装了swftools可以将pdf转换为swf文件,然后配合一个FlexPaper,就可以做成和百度图文库类似的东东了. 但是今天,我们开发的同事告诉我说pwd转换的这个会有乱码问题,我看了一 ...

  7. linux mysql 乱码怎么解决_MySQL_linux中解决mysql中文乱码方法,改默认编码:/etc/init.d/my - phpStudy...

    linux中解决mysql中文乱码方法 改默认编码: /etc/init.d/mysql start (stop) 为启动和停止服务器 /etc/mysql/ 主要配置文件所在位置 my.cnf /v ...

  8. linux中mysql不显示中文_linux中解决mysql中文乱码方法

    改默认编码: /etc/init.d/mysql start (stop) 为启动和停止服务器 /etc/mysql/ 主要配置文件所在位置 my.cnf /var/lib/mysql/ 放置的是数据 ...

  9. Activiti保存.png 流程图片文件且解决idea中保存图片时显示中文乱码的解决方法

    Activiti保存.png 流程图片文件且解决idea中保存图片时显示中文乱码的解决方法 Eclipse 工具中的操作 流程图片生成的两种方式: 使用 activiti-designer 设计流程图 ...

最新文章

  1. 60颗卫星被五手火箭送上天!马斯克疯狂的卫星互联网计划不远了
  2. Spring实战之二:装配Bean
  3. MacOS中安装python-jekins失败解决方法
  4. 思考:Linux Kernel的中断处理函数中是否会被其它程序(中断/异常)打断?
  5. 第24天学习Java的笔记-接口Interface
  6. 【CV】ECCV2020图像分割开源论文合集
  7. Integer 中的缓存类IntegerCache
  8. SLF4J简介与使用(整合log4j)
  9. idea2019打卡没多久就闪退_IDEA 2020.1打开时闪退的问题及解决方法(完美解决方法)...
  10. TypeError: to_categorical() got an unexpected keyword argument 'nb_classes'
  11. 华为2022校园赛——车道渲染
  12. 【Word】利用域代码快速实现自定义编号
  13. ARM-linux开发板网线连接电脑访问外网
  14. 第九届河南省程序设计大赛 1273-宣传墙(java)
  15. 可视化拖拽组件库一些技术要点原理分析(三)
  16. 一图掌握ISACA五大资格证书体系
  17. RCNN,Fast RCNN, Faster RCN解析
  18. Nginx学习心得总结第一章
  19. 【考研】2022暨南大学848 电子信息(计算机技术) 经验贴 经验贴汇总
  20. k线顶分型 python_K线的顶分型与底分型(实例图解)

热门文章

  1. 安装vmtools之后任然不能在虚拟机和主机之间复制粘贴的问题
  2. java中final,static,this,supper关键字的异同
  3. video标签 设置背景图片
  4. mbp2015 款发热主因
  5. 用python画微信表情_【一点资讯】“裂开了,苦涩了,翻白眼”!我用Python画出微信新出的表情包 www.yidianzixun.com...
  6. 数据结构期末考试复习整理
  7. 3.5Bootstrap组件篇之导航条
  8. dr.fone for android,Wondershare Dr.Fone for Android
  9. skywalking获取traceId(tid)的方式
  10. 读后感----《我奋斗了18年才和你坐在一起喝咖啡》