2013-07-05 26 views
6

私の.cppファイルがjbyteArrayを取得し、printfでjbyteArrayを印刷できるJNIプログラムを作成しています。そのためには、jbyteArrayを文字配列に変換する必要があると思います。jbyteArrayを文字配列に変換してコンソールに出力する

バックグラウンドについては、JNIのJava側でStringをbyteArrayに変換し、そのbyteArrayをJNI関数の引数として渡します。

私がこれまで行ってきたことは、文字列を正しく出力しますが、その後にジャンク文字が続き、私が何か問題があった場合、これらを取り除く方法はわかりません。

dsa 

とどのような印刷物をコンソールに:ここで

は、文字列が何であるかである

dsa,� 

ジャンク文字が文字列が何であるかに応じて変化します。

.javaファイル:

public class tcr extends javax.swing.JFrame{ 

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

public native int print(byte file1[]); 

    ..... 

    String filex1 = data1TextField.getText();//gets a filepath in the form of a String from a GUI jtextfield. 
    byte file1[]= filex1.getBytes();//convert file path from string to byte array 

     tcr t = new tcr(); 
     t.print(file1); 
} 

た.cppコード:

JNIEXPORT jint JNICALL Java_tcr_print(JNIIEnv *env, jobject thisobj, jbyteArray file1){ 

    jboolean isCopy; 
    jbyte* a = env->GetByteArrayElements(file1,&isCopy); 
    char* b; 
    b = (char*)a; 
    printf("%s\n",b); 
} 

任意の助けをいただければ幸いここ は、関連するコードの一部です。

答えて

7

あなたは何をしているかを見て:

jbyte* a = env->GetByteArrayElements(file1,&isCopy); 

aは今、文字列のバイトの内容が保存されているメモリアドレスを指します。ファイルに "Hello world"という文字列が含まれているとしましょう。 UTF-8符号化では、それは次のようになります

48 65 6c 6c 6f 20 77 6f 72 6c 64

char* b = (char*)a; 

b現在、そのメモリ領域を指します。これはcharポインタなので、おそらくCの文字列として使用したいと思うでしょう。しかし、それは動作しません。 C文字列はいくつかのバイトとして定義され、0バイトで終わります。今そこを見ると、この文字列の最後にゼロバイトがないことがわかります。

printf("%s\n",b); 

ここにあります。 printfにcharポインタを渡して、にCの文字列を示す%sとしています。ただし、Cの文字列ではありませんが、printfはすべての文字をゼロバイトに達するまで印刷します。だから、dsaの後に見えるのは、バイト配列の終わりの後のあなたのメモリからのバイトであり、(一致して)ゼロバイトがあるまでです。これを修正するには、バイト配列よりも1バイト長いバッファにバイトをコピーし、最後の要素をゼロに設定します。

UPDATE:

あなたはより大きなバッファを作成し、このようなヌルバイトを追加することができます。

int textLength = strlen((const char*)a); 
char* b = malloc(textLength + 1); 
memcpy(b, a, textLength); 
b[textLength] = '\0'; 

b有効な、NULLで終了するC文字列です。また、ReleaseByteArrayElementsへの呼び出しを忘れないでください。 memcpyコールの直後にこれを行うことができます。

+0

申し訳ありませんが、非常に初心者の質問のように聞こえますが、1バイト長のバッファを作るにはどうすればいいのですか? –

+0

@SeanSenWang私の編集を参照してください。 –

+0

ありがとう、魅力的なように働いた。私はC++ではないので、malloc呼び出しが行われたときに(char *)にキャストする必要があります。 –

2

実際、jbyteArrayは、JNIを通じてJava Stringを渡す非常に良い方法です。これにより、文字列を、C++側で使用しているライブラリやファイル/デバイスが必要とする文字セットとエンコーディングに簡単に変換できます。

あなたが理解していることを確認してくださいは、 "The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)"

JavaのStringはUnicode文字セットとUTF-16エンコーディング(プラットフォーム依存のバイト順序を持つ)を使用しています。

String.getBytes()は、「プラットフォームのデフォルトの文字セット」に変換されます。だから、それはあなたが必要とする文字セットとエンコーディング、そして目標文字セットにない文字について何をすべきかについて仮定しています。これらのものを明示的に制御したい場合は、他のJava String.getBytesオーバーロードまたはCharsetメソッドを使用できます。

使用する文字セットとエンコーディングを決めるにあたって、Java、.NET、VB、...の主な文字列型としてUnicodeが数十年使用されていると考えてください。 Javaのコンパイラソースファイルでは、...;一般的にはWWWである。もちろん、あなたは相互運用したいものによって制限されるかもしれません。

現在、ターゲット文字セットにJava文字列があり、代替文字が使用されていないか、使用しているコンソールが正しく表示されていないという問題が発生しているようです。

コンソール(またはUIを持つアプリ)は、明らかに文字を表示する書体を選択する必要があります。書体は一般に、Unicodeで利用可能な百万のコードポイントをサポートしていません。コンソールの設定を変更する(または別の設定を使用する)ことができます。たとえば、Windowsでは、cmd.exeまたはps(Windows PowerShell)を使用できます。 Cmd.exeウィンドウでフォントを変更し、chcpを使用して文字セットを変更できます。

UPDATE:

@ main--が指摘するように、あなたが文字列に追加ターミネータを期待する機能を使用する場合、JVMはの所有権を保持しているので、あなたは、通常の配列をコピーし、それを提供する必要がありますアレイ。この場合の動作の実際の原因。しかし、上記のすべてが関連しています。

+0

この場合、問題はありません。私の答えを見てください。 –

関連する問題