web-dev-qa-db-fra.com

Java - Chargement de DLL par un chemin relatif et cachez-les à l'intérieur d'un pot

PARTIE 1

Je développe un Java application qui devrait être publié comme un pot. Ce programme dépend des bibliothèques externes C++ appelées par JNI. Pour les charger, j'utilise la méthode System.load Avec un chemin absolu et cela fonctionne bien.

Cependant, je veux vraiment les "cacher" les "cacher" à l'intérieur du pot, j'ai donc créé un paquet pour les collecter. Cela me force à charger un chemin relatif - le chemin d'emballage. Par cette approche, je laisse l'utilisateur exécuter le pot dans n'importe quel répertoire, sans être inquiet de relier les DLL ou de s'ennuyer avec un processus d'installation précédent.

Cela jette l'exception attendue:

Exception dans le fil "Main" Java.lang.unsatisfiedLinkError: Attender un chemin absolu de la bibliothèque

Comment puis-je obtenir ce travail?

PARTIE 2

L'approche de la copie des DLL vers un dossier (expliqué ci-dessous) ne fonctionne que lorsque je l'exécute sous l'environnement Eclipse. Exécution d'un pot exporté, le DLL binaires est bien créé mais le chargement de la JNI One jette la prochaine exception:

Exception dans le fil "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)

J'exécute cette méthode de chargement:

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

Je pense que cela pourrait être un problème de privilèges d'accès, mais je ne sais pas comment résoudre. Qu'est-ce que tu penses?

20
supertreta

Je ne crois pas que vous puissiez charger le DLL directement du pot. Vous devez prendre l'étape intermédiaire de la copie DLL hors du pot. Le Le code suivant devrait le faire:

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

Ce jarclassloader visant à résoudre le même problème:

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

2
AlexV