Java – загрузка DLL по относительному пути и скрыть их внутри банки

ЧАСТЬ 1

Я разрабатываю приложение Java, которое должно быть выпущено как банку. Эта программа зависит от внешних библиотек C ++, называемых JNI. Чтобы загрузить их, я использую метод System.load с абсолютным путем, и это работает отлично.

Тем не менее, я действительно хочу «спрятать» их внутри JAR, поэтому я создал пакет для их сбора. Это заставляет меня загружать относительный путь – путь пакета. Благодаря такому подходу я разрешаю пользователю запускать JAR в любом каталоге, не беспокоясь о необходимости связывать библиотеки DLL или скучать с предыдущим процессом установки.

Это вызывает ожидаемое исключение:

Исключение в streamе «main» java.lang.UnsatisfiedLinkError: ожидая абсолютный путь библиотеки

Как я могу заставить это работать?

ЧАСТЬ 2

Подход к копированию DLL в папку (объясняется ниже) работает только при запуске в среде eclipse. Запуск экспортированного JAR, двоичные файлы DLL хорошо созданы, но загрузка JNI создает следующее исключение:

Исключение в streamе “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) 

Я запускаю этот метод загрузки:

 public static void loadBinaries(){ String os = System.getProperty("os.name").toLowerCase(); if(os.indexOf("win") >= 0){ ArrayList bins = new ArrayList(){{ 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()); } } 

Я думаю, что это может быть проблема с правами доступа, но не знаю, как ее решить. Как вы думаете?

    Я не верю, что вы можете загрузить DLL непосредственно из JAR. Вы должны предпринять промежуточный шаг по копированию DLL из JAR. Следующий код должен сделать это:

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

    В принципе это должно сработать. Так как это делает JNA, просто загрузите его и изучите код. У вас даже есть некоторые подсказки, чтобы сделать эту платформу независимой …

    РЕДАКТИРОВАТЬ

    JNA приносит свой собственный код вместе в банке, распаковывает правильный двоичный файл во время выполнения и загружает его. Это может быть хорошей моделью (если я правильно понял ваш вопрос).

    Этот JarClassLoader стремится решить ту же проблему:

    http://www.jdotsoft.com/JarClassLoader.php

    Вам нужно закодировать загрузчик classов с расположением DLL, но его можно загрузить без извлечения из банки. Достаточно простого перед выполнением вызова загрузки. В вашем основном classе добавьте:

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

    Примечательно, что я столкнулся с одной и той же проблемой с обработкой JNA и OSGi, как загружаются DLL .

    Давайте будем гением компьютера.