JNI乱码问题

我们看看我们从java通过native方法传入一个字符串给c函数,并在c函数输出

JAVA源码:

package com.fmy;

import java.io.UnsupportedEncodingException;

public class FMY {


    static{
        System.loadLibrary("Project2");
    }

    public static void main(String[] args) {

        String argunment = "你好!";
        callFile(argunment);
    }


    public native static void callFile(String path);


}

C源码:

#include"com_fmy_FMY.h"

JNIEXPORT void JNICALL Java_com_fmy_FMY_callFile
(JNIEnv * env, jclass jcl, jstring jsring){

    char * JAVAchars=(*env)->GetStringUTFChars(env, jsring, NULL);

    printf("在c中输出传入的字符串%s",JAVAchars);

}

输出 ��c�����������ַ���你好!

  • 解释:
    1. java源码是用UTF-8存储
    2. C源码是GB2312存储
    3. 在java打印的UTF-8格式 那么也就说 在c语言执行的printf输出语句的时候,”在c中输出传入的字符串”为GB2312格式输出到java ,而占位符%s 为UTF-8格式(前面调用GetStringUTFChars方法) 所以导致以上输出结果

那么我们假设更换C或者java源文件的编码统一 为GB2312和UTF-8呢?

  • 把java更改为GBK格式
package com.fmy;

import java.io.UnsupportedEncodingException;

public class FMY {


    static{
        System.loadLibrary("Project2");
    }

    public static void main(String[] args) {

        String argunment = "浣犲ソ!";
        callFile(argunment);
    }


    public native static void callFile(String path);


}

发现源文件乱码

c中输出传入的字符串娴g姴銈?!

发现传入的字符串又乱码了 ,”g姴銈?!”和”浣犲ソ!”完全不一样,是不是因为更换gbk后源文件乱码没修改?那么我们再试试

把java修改为GBK之后的乱码修改

package com.fmy;

import java.io.UnsupportedEncodingException;

public class FMY {


    static{
        System.loadLibrary("Project2");
    }

    public static void main(String[] args) {

        String argunment = "你好";
        callFile(argunment);
    }


    public native static void callFile(String path);


}

输出:

在c中输出传入的字符串浣犲ソ

依然乱码

  • 解决思路:

    1. 因为传入”你好”的是GBK编码但是在c中使用此函数导致了GBK转化为UTF-8格式
      (*env)->GetStringUTFChars(env, jsring, NULL);
      所以说我们在c中将UTF-8中转化即可 以下代码用到windows.h 这个库用到的函数详解
#include"com_fmy_FMY.h"
#include<Windows.h>

char* Utf8ToGb2312(char *p);

JNIEXPORT void JNICALL Java_com_fmy_FMY_callFile
(JNIEnv * env, jclass jcl, jstring jsring){

    char * cstr = (*env)->GetStringUTFChars(env, jsring, NULL);



    printf("在c中输出传入的字符串%s", Utf8ToGb2312(cstr));



}



/*************************************************
*将GB2312编码的字符串转为UTF-8编码
*输入:
*p:指向待转码字符串
*返回:
*指向已转码字符串的指针
*过程:
*将GB2312转为Unicode编码
*再将Unicode转为UTF-8
*************************************************/
char* Gb2312ToUtf8(char *p){
    DWORD dwNum = MultiByteToWideChar(CP_ACP, 0, p, -1, NULL, 0);
    char *psText;
    wchar_t *pwText = (wchar_t*)malloc(dwNum*sizeof(wchar_t));
    dwNum = MultiByteToWideChar(CP_ACP, 0, p, -1, pwText, dwNum);
    dwNum = WideCharToMultiByte(CP_UTF8, 0, pwText, -1, NULL, 0, NULL, NULL);
    psText = (char*)malloc(dwNum*sizeof(char));
    dwNum = WideCharToMultiByte(CP_UTF8, 0, pwText, -1, psText, dwNum, NULL, NULL);
    free(pwText);
    return psText;
}

/*************************************************
*将UTF-8编码的字符串转为GB2312编码
*输入:
*p:指向待转码字符串
*返回:
*指向已转码字符串的指针
*过程:
*将UTF-8转为Unicode编码
*再将Unicode转为GB2312
*************************************************/
char* Utf8ToGb2312(char *p){
    DWORD dwNum = MultiByteToWideChar(CP_UTF8, 0, p, -1, NULL, 0);
    char *psText;
    wchar_t *pwText = (wchar_t*)malloc(dwNum*sizeof(wchar_t));
    dwNum = MultiByteToWideChar(CP_UTF8, 0, p, -1, pwText, dwNum);
    dwNum = WideCharToMultiByte(CP_ACP, 0, pwText, -1, NULL, 0, NULL, NULL);
    psText = (char*)malloc(dwNum*sizeof(char));
    dwNum = WideCharToMultiByte(CP_ACP, 0, pwText, -1, psText, dwNum, NULL, NULL);
    free(pwText);
    return psText;
}

linux下可以用链接中的函数库

输出:在c中输出传入的字符串你好

tip:把c源文件改为UTF-8也可以哦,解决步骤和上面差不多

jni返回一个字符串乱码

现在 c文件是默认的GB2312 ,java是UTF-8

java源码:

package com.fmy;

import java.io.UnsupportedEncodingException;

public class FMY {


    static{
        System.loadLibrary("Project2");
    }

    public static void main(String[] args) {


        String fromC = callFile();

        System.out.println(fromC);

    }


    public native static String callFile();


}
  • c函数实现:

    JNIEXPORT jstring JNICALL Java_com_fmy_FMY_callFile
    (JNIEnv * env, jclass jcl){
    
        return (*env)->NewStringUTF(env,"嘿嘿是的!!!");
    
    }
    

    输出:ºٺÙÊǵÄ!!

  • 解决办法:
    把c源文件保存为UTF-8 不带签名类型的文件

    输出:嘿嘿是的!!!

    tip:当然你也可以试试吧java换gbk

  • 解决办法2:

    由于在c中写字符串是GB2312那么用string的构造方法构造出gb2312格式即可完成

    JNIEXPORT jstring JNICALL Java_com_fmy_FMY_callFile
    (JNIEnv * env, jclass jcs){
    
        char *cstr = "我说中文?";
        //String类的jclass
        jclass str_cls = (*env)->FindClass(env, "java/lang/String");
        jmethodID constructor_mid = (*env)->GetMethodID(env, str_cls, "<init>", "([BLjava/lang/String;)V");
    
        //char * -> char[] ->jbyteArray -> jbyte * 
        jbyteArray bytes = (*env)->NewByteArray(env, strlen(cstr));
        //bytes数组赋值
        (*env)->SetByteArrayRegion(env, bytes, 0, strlen(cstr), cstr);
    
    
        jstring charsetName = (*env)->NewStringUTF(env, "gb2312");
    
        //
        return (*env)->NewObject(env, str_cls, constructor_mid, bytes, charsetName);
    }

    输出:嘿嘿!!!!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值