Java - загрузка DLL по относительному пути и скрытие их в банке - PullRequest
19 голосов
/ 14 января 2011

ЧАСТЬ 1

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

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

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

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

Как мне это работает?

PART 2

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

Исключение в потоке "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<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());
        }
    }

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

Ответы [ 4 ]

26 голосов
/ 14 января 2011

Я не верю, что вы можете загрузить 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());
}
2 голосов
/ 04 апреля 2012

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

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

2 голосов
/ 14 января 2011

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

EDIT

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

0 голосов
/ 15 января 2011

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

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

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

...