2011-01-14 15 views
16

भाग 1

मैं जावा एप्लिकेशन विकसित कर रहा हूं जिसे जार के रूप में रिलीज़ किया जाना चाहिए। यह कार्यक्रम जेएनआई द्वारा बुलाए गए सी ++ बाहरी पुस्तकालयों पर निर्भर करता है। उन्हें लोड करने के लिए, मैं एक पूर्ण पथ के साथ विधि System.load का उपयोग करता हूं और यह ठीक काम करता है।जावा - एक सापेक्ष पथ से डीएलएस लोड हो रहा है और उन्हें एक जार

हालांकि, मैं वास्तव में उन्हें जार के अंदर "छिपाना" चाहता हूं, इसलिए मैंने उन्हें एकत्र करने के लिए एक पैकेज बनाया है। यह मुझे एक सापेक्ष पथ - पैकेज पथ लोड करने के लिए मजबूर करता है। इस दृष्टिकोण से, मैंने डीएलएल को जोड़ने या पिछली स्थापना प्रक्रिया से ऊबने के बारे में चिंतित किए बिना उपयोगकर्ता को किसी भी निर्देशिका में JAR चलाने दिया।

यह उम्मीद अपवाद फेंकता है:

Exception in thread "main" java.lang.UnsatisfiedLinkError: Expecting an absolute path of the library

मैं इस काम के कैसे मिल सकता है?

भाग 2

एक फ़ोल्डर में DLLs को कॉपी करने की दृष्टिकोण (नीचे समझाया) ही काम करता है जब मैं ग्रहण वातावरण के अंतर्गत इसे चलाने के।

Exception in thread "main" java.lang.reflect.InvocationTargetException

at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:56) 
Caused by: java.lang.UnsatisfiedLinkError: C:\Users\Supertreta\Desktop\nm files\temp\jniBin.dll: Can't find dependent libraries at java.lang.ClassLoader$NativeLibrary.load(Native Method) 

मैं इस लदान विधि चलाएँ:: एक निर्यात जार चल रहा है, DLL बाइनरी अच्छी तरह से बनाई गई हैं, लेकिन JNI एक लोड हो रहा है अगले अपवाद फेंकता

public static void loadBinaries(){ 
     String os = System.getProperty("os.name").toLowerCase(); 

     if(os.indexOf("win") >= 0){ 
      ArrayList<String> bins = new ArrayList<String>(){{ 
       add("/nm/metadata/bin/dependence1.dll"); 
       add("/nm/metadata/bin/dependence2.dll"); 
       add("/nm/metadata/bin/dependence3.dll"); 
       add("/nm/metadata/bin/dependence4.dll"); 
       add("/nm/metadata/bin/jniBin.dll"); 
      }}; 

      File f = null; 
      for(String bin : bins){ 
       InputStream in = FileManager.class.getResourceAsStream(bin); 
       byte[] buffer = new byte[1024]; 
       int read = -1; 
       try { 
        String[] temp = bin.split("/"); 
        f = new File(TEMP_FOLDER, temp[temp.length-1]);  
        FileOutputStream fos = new FileOutputStream(f); 

        while((read = in.read(buffer)) != -1) { 
         fos.write(buffer, 0, read); 
        } 
        fos.close(); 
        in.close(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 

      System.load(f.getAbsolutePath()); 
     } 
    } 

मुझे लगता है कि यह एक पहुँच विशेषाधिकार समस्या हो सकती है , लेकिन यह नहीं पता कि इसे कैसे हल किया जाए। तुम क्या सोचते हो?

+0

क्यों आप उन्हें छिपाने के लिए करना चाहते हैं? –

+0

एक साफ जार प्रदान करने के लिए – supertreta

उत्तर

21

मुझे विश्वास नहीं है कि आप सीधे जेएआर से डीएलएल लोड कर सकते हैं। आपको जेएआर से डीएलएल की प्रतिलिपि बनाने का मध्यस्थ कदम उठाना होगा। निम्नलिखित कोड यह करना चाहिए:

public static void loadJarDll(String name) throws IOException { 
    InputStream in = MyClass.class.getResourceAsStream(name); 
    byte[] buffer = new byte[1024]; 
    int read = -1; 
    File temp = File.createTempFile(name, ""); 
    FileOutputStream fos = new FileOutputStream(temp); 

    while((read = in.read(buffer)) != -1) { 
     fos.write(buffer, 0, read); 
    } 
    fos.close(); 
    in.close(); 

    System.load(temp.getAbsolutePath()); 
} 
+0

यह मुझे इस मुद्दे को हल करने का एक त्वरित और आसान तरीका प्रतीत होता है। मैंने कोशिश की लेकिन मुझे कोई समस्या है: createTempFile विधि फ़ाइल के नाम पर एक संख्या जोड़ती है, यानी lib "hello.dll" इन पैरामीटर (नाम, "") के साथ भी "hello.dll4975093656535427331" बन जाती है।मेरा प्राथमिक जेएनआई डीएल भी अन्य डीएलएस पर निर्भर करता है इसलिए मुझे नामों के बारे में अवगत होना चाहिए। क्या आप जानते हैं कि मैं इससे कैसे निपट सकता हूं? – supertreta

+0

हां, बस 'फ़ाइल temp' प्रारंभ करने के तरीके को बदलें:' फ़ाइल temp = नई फ़ाइल (नई फ़ाइल (System.getProperty ("java.io.tmpdir")), नाम) '; –

+0

अब मैं सभी डीएलएल फाइलों की प्रतिलिपि बनाता हूं लेकिन जब मैं जेएनआई लोड करता हूं तो मुझे अगला अपवाद मिलता है: थ्रेड "अप" में अपवाद java.lang.UnsisfisfiedLinkError: सी: \ दस्तावेज़ और सेटिंग्स \ प्रशासक \ स्थानीय सेटिंग्स \ Temp \ hello.dll : यह एप्लिकेशन प्रारंभ करने में विफल रहा है क्योंकि अनुप्रयोग कॉन्फ़िगरेशन गलत है। अनुप्रयोग पुनर्स्थापित कर इस समस्या का हल किया जा सकता है। मैंने पुष्टि की कि सभी पुस्तकालय अस्थायी फ़ोल्डर में हैं ... – supertreta

2

असल में यह काम करना चाहिए। चूंकि जेएनए ऐसा करता है, बस इसे डाउनलोड करें और कोड का अध्ययन करें। आप भी इस मंच स्वतंत्र बनाने के लिए कुछ संकेत

JNA, जार में साथ अपने मूल कोड लाता क्रम und यह भार पर सही द्विआधारी unpacks है ...

संपादित करें। यह पालन करने के लिए एक अच्छा पैटर्न हो सकता है (अगर मुझे आपका प्रश्न सही मिला)।

+3

क्षमा करें, क्या आपको अपने उत्तर पर कुछ याद आया? "यह" के साथ आप क्या देखते हैं? धन्यवाद – supertreta

-1

आप प्रधानमंत्री को DLL के स्थान के साथ classloader की जरूरत है - लेकिन यह जार से निकाल बिना लोड किया जा सकता। लोड कॉल निष्पादित होने से पहले कुछ आसान है। आपका मुख्य वर्ग ऐड में:

static { 
    System.loadLibrary("resource/path/to/foo"); // no .dll or .so extension! 
} 

विशेष रूप से, मैं मूल रूप से एक ही issue with JNA and OSGi's handling of how the DLLs are loaded का अनुभव किया।

+0

मुझे लगता है कि मैं इसे ठीक से चलाता हूं। और यह ठीक काम करता है जब मैं इसे ग्रहण पर डीबग कर रहा हूं। समस्या तब प्रकट होती है जब मैं एक जार निर्यात करता हूं और इसे चलाता हूं। मैंने अपनी लोडिंग विधि के साथ जवाब अपडेट किया। धन्यवाद! – supertreta

+0

@supertreta: मुझे यकीन है कि आप अपने जेएआर में डीएलएल पैक नहीं कर रहे हैं। अपने जेएआर को एक ज़िप फ़ाइल में बदलने और इसे एक्सप्लोर करने का प्रयास करें। –

+0

मैं जार को फ़ोल्डर पर डीएलएस बना सकता हूं। मैंने इसे चलाने से पहले इसे हटाने की पुष्टि की। मैंने अब इसे एक ज़िप में परिवर्तित करने की जांच की है, और वे वहां हैं। – supertreta