2013-08-06 4 views
7

का उपयोग कर जावा पर लौटाना मेरे पास एक जेएनआई फ़ंक्शन है, जो सी ++ में लिखा गया है, जो एक बाइट सरणी इनपुट के रूप में लेता है, इसे सेगमेंट करता है, और जावा में बाइट एरे की एक सरणी देता है।सी ++ में एक बाइट [] [] बनाना और जेएनआई

जेएनआईएक्सपोर्ट जॉबजेक्टएरे जेएनआईसीएलएल जावा_क्लास_एम विधि (जेएनआईएनएनवी * एनवी, जॉबजेक्ट ओ, जेबीटेएरे डेटा टू सेगमेंट);

जावा पक्ष पर, यह उतना ही आसान कुछ के रूप में बताया गया है:

byte[] arg = getRandomByteArray(); 
Object[] retVal = x.method(arg); 

अब, मैं JNI हिस्सा पाने के कर रहा हूँ थोड़ी सूझबूझ से काम किया जाना है। मैं ऑब्जेक्ट्स की एक सरणी बनाने का इरादा रखता हूं, जिनमें से प्रत्येक एक बाइट सरणी है। ऐसा इसलिए है क्योंकि जेएनआई केवल सीमित प्रकार के जावा प्रकारों को परिभाषित करता है। एक jbyteArray प्रकार है, और एक jobjectArray प्रकार है, लेकिन कोई jarrayOfByteArrays प्रकार नहीं है।

jobjectArray retVal = env->NewObjectArray(numSegs, env->FindClass("[Ljava/lang/Object;"), env->NewByteArray(1024)); 

मैं तो इस सरणी में भर अनुक्रमित पुनरावृति, की तरह कुछ कर रही:

jbyteArray tmp = (jbyteArray) env->GetObjectArrayElement(retVal, i); 
env->SetByteArrayRegion(tmp, 0, size, (jbyte*) sourceBuffer); 
env->SetObjectArrayElement(retVal, i, (jobject) tmp); // <--- Questionable line 

तो मैं वस्तुओं के अपने सरणी बनाने के लिए, प्रत्येक वस्तु एक नया बाइट [1024] के रूप में प्रारंभ किया जा रहा

और अधिकांश भाग अधिकांश के लिए बहुत अच्छा काम करता है। हालांकि, अगर मैं प्रत्येक बाइट सरणी को चर की लंबाई के लिए चाहता था तो क्या होगा? यही है, मैं बाइट एरे की सरणी को "जंजीर" होना चाहता हूं। प्रारंभिक मान के रूप में मैं NewObjectArray() को अंतिम पैरामीटर के रूप में क्या पास करूं? मैंने jobjectArray निर्माण के समय प्रारंभिक मान को रोकने के लिए प्रारंभिक मान के रूप में 0 को पार करने का प्रयास किया है, और उसके बाद SetObjectArrayElement() को पास करने के लिए नई jbyteArray ऑब्जेक्ट्स आवंटित करने की कोशिश की है, लेकिन यह केवल जब मैं SetObjectArrayElement को कॉल करने का प्रयास करता हूं तो यह केवल ArrayStoreException को फेंक देगा। दरअसल, tmp ऑब्जेक्ट को एक नया jbyteArray भी निर्दिष्ट करना (GetObjectArrayElement() से एक के बजाय) SetObjectArrayElement() को कॉल करते समय उसी अपवाद को फेंक दिया जाता है। क्या कोई कारण है कि कोड की आखिरी पंक्ति एक मुद्दा होगा? क्या एक पैरामीटर के रूप में jbyteArray के साथ SetObjectArrayElement() को कॉल करना संभव नहीं है?

ऐसा लगता है कि आगे निरीक्षण पर, "संदिग्ध रेखा" कुछ भी नहीं कर रही है। जब मैं इसे टिप्पणी करता हूं, तो टीएमपी में किए गए कोई भी बदलाव retVal में दिखाई देते हैं। मैं समझता हूं कि ऐसा इसलिए है क्योंकि SetByteArrayRegion कॉल बाइट सरणी से निपट रहा है जो jobjectArray में "इन" है, और एक प्रति नहीं। यह मेरे लिए पर्याप्त होगा यदि सभी पंक्तियां (बल्कि, सभी एकल-आयामी बाइट सरणी) एक ही लंबाई थीं। लेकिन वे नहीं हैं। मैं इस ऑब्जेक्ट सरणी में पंक्तियों में से किसी एक को एक नया बाइट सरणी कैसे सौंपूं?

टीएल; डीआर: जेएनआई के साथ, मेरे पास जॉबटेअरेज़ का नौकरी है। मैं न्यूबेटएरे के साथ बनाई गई एक नई चीज़ के साथ jbyteArrays में से किसी एक को कैसे बदलूं? संकेत: env-> SetObjectArrayElement (retVal, i, (jobject) env-> NewByteArray (आकार)); // काम नहीं करता है।

उत्तर

2

आप JNI के बजाय JNA उपयोग करने का विकल्प है, तो आप JNA API दस्तावेज़ पेज में प्रदान की जाती उदाहरण के साथ कुछ इसी तरह का उपयोग करने में सक्षम होना चाहिए:

http://jna.java.net/javadoc/overview-summary.html#arrays

"एक देशी नक़्शा बनाने के लिए बहु-आयामी सरणी, पूर्ण देशी सरणी के बराबर कई तत्वों के साथ एक एकल-आयामी जावा सरणी का उपयोग करें "

+0

धन्यवाद, लेकिन दुर्भाग्य से मैं यहां जेएनआई के साथ फंस गया हूं। –

+0

@SzymonSmakolski बफर आवंटित करने के लिए जेएनआई कोड से NewDirectByteBuffer का उपयोग करें। – Eugene

+0

मेरी [सीमित] समझ के आधार पर, NewDirectByteBuffer देशी पक्ष पर आवंटित स्मृति के साथ काम करता है। मैं JVM को जावा बाइट [] ऑब्जेक्ट्स का एक गुच्छा आवंटित करना चाहता हूं जिसे मैं किसी ऑब्जेक्ट में क्रैक कर सकता हूं []। आपके द्वारा सुझाए गए दृष्टिकोण में मुझे सी ++ के नए ऑपरेटर का उपयोग करके प्रत्येक बाइट एरे आवंटित करना होगा, न कि JVM। मैं जेवीएम को जावा पक्ष पर वास्तव में समाप्त होने वाले किसी भी डेटा के आवंटन को संभालने देना चाहता हूं। –

3

मैंने सफलतापूर्वक जेएनआई के माध्यम से बाइट सरणी की सरणी वापस कर दी।प्रारंभिक आकार अपने बाइट सरणी के कोई फर्क नहीं पड़ता, क्योंकि आप इसे एक नया एक के साथ बदलें के रूप में आप jobject सरणी पॉप्युलेट:

static jbyteArray NewJavaStringBytes(JNIEnv* env, const char *src) { 
    jbyteArray retVal = (*env)->NewByteArray(env, strlen(src)); 
    jbyte *buf = (*env)->GetByteArrayElements(env, retVal, NULL); 
    strcpy(buf, src); 
    printf(" NewJavaStringBytes: Created java byte array: %s.\n", buf); 
    (*env)->ReleaseByteArrayElements(env, retVal, buf, 0); 

    return retVal; 
} 

JNIEXPORT jobjectArray JNICALL Java_TestJniString_printStringArray 
    (JNIEnv *env, jobject thisObj, jobjectArray jObjArr) { 
    int numStr = (*env)->GetArrayLength(env, jObjArr); 
    int idx = 0; 
    jobjectArray strArr = NULL; 
    jbyte *curStr = NULL; 
    jclass arrayElemType = (*env)->FindClass(env, "[B"); 

    const char *retStrs[] = {"one", "two", "three", "twenty-five", "TESTING!!"}; 
    const int RET_LEN = sizeof(retStrs)/sizeof(char *); 

    printf("Creating java object array of %d items.\n", RET_LEN); 
    //Create new array of byte array 
    jobjectArray testArray = (*env)->NewObjectArray(env, 
                RET_LEN, 
                arrayElemType, 
                (*env)->NewByteArray(env, 1)); 

    for (idx = 0; idx < RET_LEN; ++idx) { 
     printf("Creating java byte array %d from str: %s.\n", idx, retStrs[idx]); 
     jbyteArray str = NewJavaStringBytes(env, retStrs[idx]); 
     (*env)->SetObjectArrayElement(env, testArray, idx, str); 
     (*env)->DeleteLocalRef(env, str); 
    } 

    printf("printStringArray: Printing %d strings:\n", numStr); 
    for (idx = 0; idx < numStr; ++idx) { 
     strArr = (*env)->GetObjectArrayElement(env, jObjArr, idx); 
     curStr = (*env)->GetByteArrayElements(env, strArr, NULL); 
     printf(" %s.\n", curStr); 
     (*env)->ReleaseByteArrayElements(env, (jbyteArray)strArr, curStr, 0); 
    } 

    (*env)->DeleteGlobalRef(env, arrayElemType); 

    return testArray; 
} 

यह उदाहरण बाइट सरणियों की एक सरणी लेता है और बाइट सरणियों की एक सरणी देता है। ध्यान दें कि यह सी (सी ++ नहीं) में है, इसलिए जेनी कॉल (* env) -> (env, ...) ;. सी ++ में रैपर कॉल को सरल बनाते हैं। साथ ही, ध्यान दें कि यह मानता है कि जावा कोड मूल परत पर भेजने से पहले स्ट्रिंग के बाइट सरणी संस्करण पर शून्य टर्मिनेटर जोड़ता है। यदि आप उस पर भरोसा नहीं कर सकते हैं, तो आपको सी/सी ++ कोड में मैन्युअल रूप से शून्य शब्द जोड़ना होगा क्योंकि जावा स्ट्रिंग से कनवर्ट करते समय बाइट [] के लिए ऐसा नहीं करेगा।

उम्मीद है कि मदद करता है।

संबंधित मुद्दे