2013-07-05 7 views
6

Ich schreibe ein JNI-Programm, wo meine .cpp-Datei ein JbyteArray erhält und ich in der Lage sein soll, das JbyteArray mit printf zu drucken. Damit das passiert, muss ich das jbyteArray in ein Zeichen-Array konvertieren.Konvertieren von jbyteArray in ein Zeichenarray und dann Drucken auf Konsole

Für Hintergrundwissen konvertiert die Java-Seite meines JNI einen String in ein ByteArray, und dann wird dieses ByteArray als ein Argument an meine JNI-Funktion übergeben.

Was ich bisher gemacht habe, druckt den String korrekt aus, aber es folgen Junk-Zeichen, und ich weiß nicht, wie ich diese loswerden soll/wenn ich etwas falsch mache. Hier

ist, was der String ist:

dsa 

und was Druck zu trösten:

dsa,� 

Die Junk-Zeichen je ändern, was der String ist. Hier ist der Teil des Codes, der relevant ist:

.java-Datei:

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-Code:

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); 
} 

Jede Hilfe würde geschätzt.

Antwort

7

Schauen Sie, was Sie tun:

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

a verweist nun auf eine Speicheradresse, wo die Byte Inhalt der Zeichenfolge gespeichert werden. Nehmen wir an, dass die Datei die Zeichenfolge "Hello world" enthält. In UTF-8-Codierung, wäre das:

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

char* b = (char*)a; 

b zeigt jetzt auf diesen Speicherbereich. Es ist ein Char-Zeiger, also möchten Sie ihn wahrscheinlich als C-String verwenden. Das wird jedoch nicht funktionieren. C-Zeichenfolgen sind als einige Bytes definiert und enden mit einem Nullbyte. Nun schaue nach oben und du wirst sehen, dass es kein Nullbyte am Ende dieser Zeichenkette gibt.

Hier ist es. Sie übergeben den Zeichenzeiger an printf als %s, die printf mitteilt, dass es eine C-Zeichenfolge ist. Es ist jedoch keine C-Zeichenfolge, aber printf versucht immer noch alle Zeichen zu drucken, bis ein Null-Byte erreicht wird. Was Sie nach dsa sehen, sind tatsächlich Bytes aus Ihrem Speicher nach dem Ende des Byte-Arrays, bis es (zufällig) ein Null-Byte gibt. Sie können dies beheben, indem Sie die Bytes in einen Puffer kopieren, der ein Byte länger ist als das Byte-Array, und dann das letzte Element auf Null setzen.

UPDATE:

Sie können die größeren Puffer erstellen und das Null-Byte wie folgt anhängen:

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

Jetzt b ist eine gültige nullterminierte C-String. Vergessen Sie auch nicht den Anruf an ReleaseByteArrayElements. Sie können dies direkt nach dem Anruf memcpy tun.

+0

Tut mir leid, wenn sich das wie eine sehr neue Frage anhört, aber wie würde ich einen Puffer machen, der ein Byte länger ist, und wie würde ich dann das letzte Element bearbeiten? –

+0

@SeanSenWang Siehe meine Bearbeitung. –

+0

danke, arbeitete wie ein Charme. Kleine Bearbeitung obwohl, ich bin in C++ nicht C, also muss ich auf (char *) werfen, wenn der malloc-Aufruf gemacht wird. –

2

Ein JbyteArray ist eigentlich eine sehr gute Möglichkeit, einen Java String über JNI zu übergeben. Es ermöglicht Ihnen, die Zeichenkette einfach in den Zeichensatz und die Codierung umzuwandeln, die von den Bibliotheken und Dateien/Geräten benötigt werden, die Sie auf der C++ Seite verwenden.

Seien Sie sicher, dass Sie "The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)"

Java String verwendet den Unicode-Zeichensatz und UTF-16-Codierung (mit einer plattformabhängigen Byte-Reihenfolge) zu verstehen.

String.getBytes() konvertiert in den "standard charset" der Plattform. Es macht also eine Annahme über den Zeichensatz und die Codierung, die Sie benötigen, und was Sie mit Zeichen tun müssen, die nicht im Zielzeichensatz enthalten sind. Sie können andere Java String.getBytes-Überladungen oder die Charset-Methoden verwenden, wenn Sie diese Dinge explizit steuern möchten.

Bei der Auswahl des zu verwendenden Zeichensatzes und der Codierung sollte berücksichtigt werden, dass Unicode seit einigen Jahrzehnten als primärer Zeichenkettentyp in Java, .NET, VB, ... verwendet wird. in Kompilierquelldateien für Java, ...; allgemein im WWW. Natürlich könnten Sie durch die Dinge begrenzt sein, mit denen Sie zusammenarbeiten wollen.

Nun scheint es, dass das Problem, dem Sie gegenüberstehen, entweder darin liegt, dass dem Zielzeichensatz Zeichen fehlen, die Ihr Java String hat und ein Ersatz verwendet wird, oder die Konsole, die Sie verwenden, zeigt sie nicht richtig an.

Die Konsole (oder jede App mit einer Benutzeroberfläche) muss natürlich eine Schriftart auswählen, mit der die Zeichen gerendert werden. Schriften unterstützen im Allgemeinen nicht die in Unicode verfügbaren Millionen Codepoints. Sie können möglicherweise die Konfiguration Ihrer Konsole ändern (oder eine andere verwenden). In Windows können Sie beispielsweise cmd.exe oder ps (Windows PowerShell) verwenden. Sie können die Schriftart in Cmd.exe-Fenstern ändern und chcp verwenden, um den Zeichensatz zu ändern.

UPDATE:

Wie @ main-- weist darauf hin, wenn Sie eine Funktion verwenden, die ein Terminator dann an die Zeichenfolge angefügt erwartet Sie es schaffen, in der Regel durch das Array zu kopieren, da die JVM das Eigentum an der behält Array. Dies ist in diesem Fall die eigentliche Ursache des Verhaltens. Aber all das ist auch relevant.

+0

Das ist nicht das Problem in diesem Fall. Sieh dir meine Antwort an. –

Verwandte Themen