jni和C 中文乱码

项目开发中:
需要传字符串进入JNI 层,也可能传出字符串。其中字符有中文,从底层传出就有乱码问题了

概念、图来自
(http://www.cnblogs.com/bluesky4485/archive/2011/12/13/2285802.html)

需要明确几个关于编码的基本概念:

  • java内部是使用的16bit的unicode编码(utf-16)来表示字符串的,无论英文还是中文都是2字节;
  • jni内部是使用utf-8编码来表示字符串的,utf-8是变长编码的unicode,一般ascii字符是1字节,中文是3字节;
  • c/c++使用的是原始数据,ascii就是一个字节,中文一般是GB2312编码,用2个字节表示一个汉字。 jni的中文字符串处理

先从字符流的方向分别对java–>C++和C++–>java进行分析

1. java–>C++

这种情况下,java调用的时候使用的是utf-16编码的字符串,jvm把这个参数传递给jni,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++部分进行编码转换就是一个必须了。

方法一:
通过String的方法来改变 字符乱码的现象 new String(byte[],charset);
思路 从c中取调用String的构造方法来实现转码

  1. 拿到String类 通过FindClass
  2. 拿到String类的构造方法 通过GetMethodID
  3. 创建一个空的NewByteArray (用来存放char) 不用char[]因为 java中byte[]对应C 中char*
  4. 把C中的char* 赋值到 NewByteArray中
  5. 调用String中构造方法 返回字符
    char* result ="C代码中的中文";

    //1:jclass (*FindClass)(JNIEnv*, const char*);  获取String类
    jclass cls_str = (*env)->FindClass(env,"java/lang/String");

    //2:jmethodID(*GetMethodID)(JNIEnv*,jclass,const char*, 
    //          const char*);
    //<init>表示初始化  获取构造方法都是用"<init>"//             "([BLjava/lang/String;)V"是签名
    jmethodID fid_str = (*env)->GetMethodID(env,cls_str,"<init>", "([BLjava/lang/String;)V");

    //3:   jbyteArray (*NewByteArray)(JNIEnv*, jsize); 创建jbyteArray
    jbyteArray jbyte = (*env)->NewByteArray(env,strlen(result));

    //4:void (*SetByteArrayRegion)(JNIEnv*, jbyteArray,jsize, jsize, 
    //             const jbyte*);
    //给 jbyte赋值
    (*env)->SetByteArrayRegion(env,jbyte,0,strlen(result),result);

    //5:  jobject     (*NewObject)(JNIEnv*, jclass, jmethodID, ...);
    //调用构造函数 得到字符串 ,并返回
    //我在这返回UTF-8才有效果 不知道原因??????
    jstring charset  = (*env)->NewStringUTF(env,"GB2312");

    return (*env)->NewObject(env,cls_str,fid_str,jbyte,charset);

方法二:
还是返回jbyteArray类型,然后Android上面再转成string类型。

方法三:
使用iconv库的(连接中的博客 就是通过这个方法)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值