- PR -

質問:JNIで日本語文字列をやりとりすると、文字化けします。

1
投稿者投稿内容
青面獣
会議室デビュー日: 2003/01/16
投稿数: 5
投稿日時: 2005-10-09 06:01
はじめまして。
Solaris 9上にて、JNIを使い、CとJavaの連携プログラムを行っています。
以下のようなプログラムを書いてみましたが
日本語の文字列(JString)がかならず文字化けします。
(今回必要なのはCからJavaへの返却部分なんですが・・・)

public class testa {
static {
System.loadLibrary("testa");
}

public native static String nihongo(String message);

protected String name;
public static void main(String[] args) {

try{
String sendMessage="123456メッセージが表示されてますか?";
/* 送る文字列 */
String receiveMessage = nihongo(sendMessage);
/* もらう文字列 */
System.out.println("java結果1:"+receiveMessage);
String string2 = new String(receiveMessage.getBytes("UNICODE"),"EUC-JP");
System.out.println("java結果2:[" + string2 + "]");
}
catch(Exception e){
System.out.println("Exception");
}
}
public byte[] getNativeChars()
{
return name.getBytes();
}
}


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "testa.h"

JNIEXPORT jstring JNICALL Java_testa_nihongo
(JNIEnv *env, jobject obj, jstring str) {

int i;
char buf[512];
jstring strr;
const jchar* jstrparam;
jstrparam = (*env)->GetStringChars(env,str,NULL);
printf("ネイティブ表示[%s]\n",jstrparam);
sprintf(buf,"テスト 文字列 123 abc");
(*env)->ReleaseStringChars(env,str,jstrparam);
// 文字列を戻す。
strr = (*env)->NewString(env,(jchar *)buf,15);
return strr;
}

どうやったら日本語を正しく返却できるのでしょうか?

(windows環境ではネイティブ側にて変換を入れているような処理を
ネット上で見かけたのですが、UNIX環境のものは見つけられませんでした。)
いっきゅう
大ベテラン
会議室デビュー日: 2004/04/04
投稿数: 153
お住まい・勤務地: 兵庫
投稿日時: 2005-10-09 12:26
C側のStringの扱いが間違えているようです。
GetStringUTFChars
ReleaseStringUTFChars
NewStringUTF
を使って下さい。

このあたりSunのJNIのチュートリアルに載ってますので
英語ですがコード部分だけでも読んで見てはどうでしょうか。
青面獣
会議室デビュー日: 2003/01/16
投稿数: 5
投稿日時: 2005-10-09 14:27
いっきゅう 様
ご返答どうもありがとうございます。

C側でのStringについて
GetStringUTFChars
ReleaseStringUTFChars
NewStringUTF
を利用するというご指摘ですが、ASCII文字列であれば問題はないのですが、
日本語ではやはり文字化けしてしまいます。

また説明の足りない部分がありましたので以下補足です。
これまでの経緯として、
・これまでASCII文字列のみを扱った文字列のやりとりはおこなっており、その部分は
ご指摘のとおりのメソッドを利用していました。(うまくいっていました)
・その後、そのやりとりに日本語の文字列を対応させることがどうしてもできませんでした。
また、調査の過程で、
http://www.ki.rim.or.jp/~kuro/Java/JNI/JNI-03.html
にて日本語のやり取りをしている箇所を見つけたのですが、
今回は環境がSolarisであるためそのままの利用ができませんでした。
ただ、Cでのコード変換ではなくJavaでのコード変換が可能であるとの
情報もあったことから最初の投稿のようなプログラムを書いてみた状況です。

またSUNのチュートリアルを読んでみようと思います。
以上、よろしくおねがいします。



いっきゅう
大ベテラン
会議室デビュー日: 2004/04/04
投稿数: 153
お住まい・勤務地: 兵庫
投稿日時: 2005-10-10 10:32
文字コードの環境について書いてないしどこでどんな文字化けかも分からないので
以下想像で
Solaris 9の文字ロケールはEUC-JP
JavaのソースなどはEUC-JPで書いてるならば

文字化けを起こしているのは
java結果1:文字化け無し
ネイティブ表示:文字化け
java結果2:文字化け

文字化けの理由は
ネイティブ表示:Unicodeを文字ロケールEUC-JPで表示しているから。
java結果2:Java側でUnicodeのStringをEUC-JPで文字化けさせているから

解決方法?
@
Solarisにiconvがあるか知らないけど
ネイティブ表示前にUNICODE→EUC-JPの変換をする。
Java側での文字コード変換は必要無し。

A
Solarisの文字ロケールをUTF-8にして
GetStringUTFCharsを使う。
ネイティブ、Javaの双方で文字コード変換は必要無し。

B
GetStringUTFCharsを使い
iconvでネイティブ表示前にUTF-8→EUC-JPの変換をする。
Java側での文字コード変換は必要無し。

が考えられます。

SolarisでJNIは経験あるけどマルチバイト文字は使わなかったので
確証ありませんが各ステップでどの文字コードを使っているか
把握すれば解決できるかと思いますのでがんばって下さい。



青面獣
会議室デビュー日: 2003/01/16
投稿数: 5
投稿日時: 2005-10-10 23:50
いっきゅう様
どうもありがとうございます。
ご指摘のとおりで、
SolarisはEUC-JP、JavaはUnicodeでの文字化けとなっていました。

あれからいろいろと調べまして、StringをgetBytesメソッドを用いて、
byte配列に変換し、その後、byte配列とエンコーディングを指定する形で
Stringを生成し、文字化けを解消いたしました。

どうもありがとうございました。
1

スキルアップ/キャリアアップ(JOB@IT)