2013-07-05 88 views
6

我正在編寫一個JNI程序,其中.cpp文件獲取jbyteArray,我希望能夠使用printf打印jbyteArray。爲了實現這一點,我相信我必須將jbyteArray轉換爲字符數組。將jbyteArray轉換爲字符數組,然後打印到控制檯

對於背景知識,我的JNI的Java端將字符串轉換爲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現在指向該存儲器區域。這是一個字符指針,所以你可能想用它作爲C字符串。但是,這是行不通的。 C字符串被定義爲一些字節,以零字節結尾。現在往上看,你會發現這個字符串的末尾沒有零字節。

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

這是它。您將字符指針傳遞給printf作爲%s,它告訴printf它是一個C字符串。但是,它不是C字符串,但printf仍會嘗試打印所有字符,直到達到零字節。所以在dsa之後你看到的是字節數組結尾後你的內存中的字節,直到出現(重合)一個零字節。您可以通過將字節複製到比字節數組長一個字節的緩衝區,然後將最後一個元素設置爲零來解決此問題。

UPDATE:

您可以創建更大的緩衝,並追加空字節是這樣的:

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

現在b是一個有效的空值終止的C字符串。另外,請不要忘記撥打電話ReleaseByteArrayElements。您可以在撥打memcpy後立即執行此操作。

+0

對不起,如果這聽起來像一個非常新手的問題,但我將如何做一個字節更長的緩衝區,然後我將如何去編輯最後一個元素? –

+0

@SeanSenWang查看我的編輯。 –

+0

謝謝,像一個魅力工作。小編輯雖然,我在C + +而不是C,所以當malloc調用時我必須轉換爲(char *)。 –

2

jbyteArray實際上是一種通過JNI傳遞Java字符串的好方法。它允許您輕鬆地將字符串轉換爲您在C++端使用的庫和文件/設備所需的字符集和編碼。

,請務必瞭解 「The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)

Java的字符串使用Unicode字符集和UTF-16編碼(與平臺相關的字節順序)。

String.getBytes()轉換爲「平臺的默認字符集」。因此,它正在假設您需要的字符集和編碼以及如何處理不在目標字符集中的字符。如果你想明確地控制這些東西,你可以使用其他Java String.getBytes重載或Charset方法。

在決定使用哪種字符集和編碼時,請考慮Unicode已被用作幾十年的Java,.NET,VB等主要字符串類型;在Java的編譯器源文件中,...;一般在WWW中。當然,你可能會受到你想要互操作的東西的限制。現在

,看來你所面臨的問題是,要麼目標字符集字符缺失您的Java字符串具有和替代中使用,或者您使用故障恢復控制檯中顯示不正常它們。

顯然,控制檯(或具有UI的任何應用程序)必須選擇一種字體來渲染字符。字體通常不支持Unicode中可用的百萬個碼點。您可能能夠更改控制檯的配置(或使用另一個)。例如,在Windows中,可以使用cmd.exe或ps(Windows PowerShell)。您可以更改Cmd.exe窗口中的字體並使用chcp來更改字符集。

UPDATE:

正如@ main--指出,如果您使用需要一個終止符附加到字符串的函數,那麼你必須自JVM保留所有權提供它,通常是通過複製陣列陣列。這是這種情況下行爲的實際原因。但是,以上所有都是相關的。

+0

這不是問題在這種情況下。看看我的答案。 –

相關問題