2009-12-04 4 views
3

J'ai une unsigned char* dans ma bibliothèque C, et j'appelle une fonction exportée par JNI qui doit définir un objet Java avec ces données, de préférence dans un byte[].Bibliothèque JNI/C: octet de passe ptr

Mais cette fonction sera appelée très souvent, et il y a pas mal de données à copier.

Est-il possible d'utiliser un ByteBuffer et d'affecter le pointeur de ce ByteBuffer à mon unsigned char*? Ou cela fonctionne-t-il seulement dans l'autre sens? Puis-je même faire cela sans copier les données?

Quel serait le meilleur moyen d'y accéder? La taille des données dans la zone unsigned char* est connue.

+0

donnez svp au moins la signature de votre méthode native en Java pour que quelqu'un puisse trouver une solution raisonnable –

+0

@Gregory: Il suffit de prendre un objet comme paramètre ... Accéder au champ n'est pas le problème, assigner un pointeur ou copier des données dans le champ byte [] est. – John

+0

Qu'est-ce qu'un problème? est-ce un problème de performance ou vous ne réussissez pas à remplir les données? –

Répondre

4

Voici une solution possible compte tenu des petites informations que vous avez fournies.

Du côté Java des choses, vous auriez:

package com.stackoverflow; 

public class JNIQuestion 
{ 
    static native void fillByteArray(byte[] buffer); 
} 

Et du côté C vous auriez:

JNIEXPORT void JNICALL Java_com_stackoverflow_JNIQuestion_fillByteArray(JNIEnv* env, jbyteArray array) 
{ 
    jboolean isCopy; 
    jbyte* buffer = (*env)->GetByteArrayElements(env, array, &isCopy); 
    jsize length = (*env)->GetArrayLength(env, array); 
    jsize i; 

    // do something with the buffer here, replace with something meaningful 
    // PAY ATTENTION TO BUFFER OVERFLOW, DO NOT WRITE BEYOND BUFFER LENGTH 
    for (i = 0; i < length; ++i) 
    buffer[i] = i; 

    // here it is important to use 0 so that JNI takes care of copying 
    // the data back to the Java side in case GetByteArrayElements returned a copy 
    (*env)->ReleaseByteArrayElements(env, buffer, 0); 
} 

En utilisant une ByteBuffer directe (ByteBuffer.allocateDirect()) est aussi une solution possible . Cependant, je n'utilise qu'un ByteBuffer direct lorsque j'ai besoin de remplir des données du côté Java d'un décalage très précis dans le tampon. A propos des performances, la solution utilisant un byte[] devrait être satisfaisante car la machine virtuelle Java est susceptible d'épingler la matrice d'octets au lieu de la copier lors de l'appel GetByteArrayElements().

De manière générale, vous souhaiterez minimiser le nombre d'appels JNI, ce qui implique que l'accès aux champs d'objet du côté C ou l'allocation de Java du côté C aura un impact sur les performances.

Dans tous les cas, profil d'abord, optimisez ensuite. PS: Je n'ai pas essayé de compiler le code, il pourrait y avoir des fautes de frappe. Reportez-vous aux JNI Guide et JNI Tutorial.

+0

Cela se rapproche, mais comment puis-je récupérer un jbyteArray à partir d'un jobject? – John

+0

vous n'avez pas besoin de; faites cela du côté Java: 'JNIQuestion.fillByteArra (myObject.getByteArray());' accéder aux champs d'objets du côté C coûte plus cher. –

+0

Ce n'est pas une option, j'ai besoin de copier les données de mon C lib en raison de structures basées sur l'événement/file d'attente ... Ce n'est pas comme si les données seront toujours là. – John