2
votes

Chemin du répertoire actuel lors de l'exécution de jar

Mon programme lit les données de configuration en lisant le fichier xml du répertoire courant:

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.10.4
Created-By: 12.0.1+12 (Oracle Corporation)
Class-Path: lib/log4j-api-2.11.2.jar lib/log4j-core-2.11.2.jar lib/met
 ouia.jar lib/swt.jar
X-COMMENT: Main-Class will be added automatically by build
Main-Class: com.aaa.myprog.runMe 

Cela fonctionne très bien dans l'EDI NetBeans. J'ai un projet de construction et un fichier jar. Cela fonctionne bien si je double-clique dessus dans Windows 10. Au cas où j'ouvre le fichier en utilisant un clic droit sur jar et que le programme Ouvrir avec -> Java ne trouve pas le fichier de configuration. Dans ce cas, j'ai une exception:

java.io.FileNotFoundException: C:\Windows\System32\configFile.xml (The system cannot find the file specified)

Pourquoi il regarde juste le chemin du système et pas dans le répertoire courant? Comment demander au programme de charger le fichier dans le répertoire courant lors de l'exécution dans le cas Ouvrir avec -> Java ?

Fichier manifeste du Jar:

File fXmlFile = new File("configFile.xml");


2 commentaires

Où réside le fichier de configuration par rapport à votre fichier jar?


Jar et le fichier de configuration sont dans le même répertoire


3 Réponses :


-1
votes

Comme je vois, le problème se pose parce que vous avez besoin de savoir comment les chemins relatifs sont résolus au moment de l'exécution , et le "répertoire courant" a lieu sur cet écuation, alors permettez-moi de vous expliquer un peu .

Pour autant que je sache, le "répertoire courant" est également appelé répertoire de travail et il est défini lorsque vous lancez une application java et prend la valeur de le répertoire à partir duquel vous exécutez la commande java pour lancer l'application .

Par exemple:

Si vous ouvrez un terminal de commande, et que vous vous placez dans un répertoire "C: \ pepe" et depuis ce répertoire vous exécutez la commande pour lancer votre jar, par exemple: java -jar "c: \ path \ to \ my \ app.jar" alors le répertoire de travail serait "c: \ pepe \" et dans votre programme toute référence à un chemin relatif serait être complété en utilisant le préfixe "c: \ pepe \" .

Et leur la ligne File fXmlFile = new File ("configFile.xml"); demandera au jvm de regarder le fichier à "c: \ pepe \ configFile.xml" < / code>, car le chemin relatif configFile.xml sera résolu en utilisant le répertoire de travail (défini précédemment au moment du lancement) comme expliqué ci-dessus.

Ayant à l'esprit comment java définit le répertoire de travail et comment les chemins relatifs sont résolus en utilisant le répertoire de travail comme préfixe, aidez-vous à résoudre tout problème de référence, à partir de maintenant!

Ce lien peut vous être utile : Obtenir le répertoire de travail actuel en Java pour rechercher quel est le répertoire de travail défini par netbeans lorsqu'il lance (pour nous) l'application java.

TD; DR:

"pepe" est le terme espagnol égal à "foo" dans le terme anglais: D, j'espère apprendre quelque chose de nouveau !! : D


5 commentaires

"Si vous exécutez c: \ pepe \ java -jar" c: \ path \ to \ my \ app.jar ", le répertoire de travail sera " c: \ pepe \ " »: ce n'est pas correct. Vous pouvez faire de n'importe quel répertoire le répertoire de travail actuel en utilisant cd , puis exécuter la même commande. Le répertoire de travail n’est pas défini par l’emplacement du programme en cours d’exécution, c’est une propriété du processus individuel ou du shell de commande parent.


merci d'avoir souligné cela, pour autant que je sache sans aucune configuration supplémentaire, votre répertoire de travail par défaut est le répertoire à partir duquel vous exécutez la commande. S'il existe un moyen supplémentaire de le définir, veuillez nous éclairer, n'hésitez pas à modifier mon message afin d'énumérer d'autres façons de définir le répertoire de travail.


cd C: \ pepe est la façon dont vous changez le répertoire de travail.


ahhh comprenez ce que vous dites, permettez-moi de réparer mon message


@VGR merci pour la suggestion, j'ai édité le message; avez-vous une autre observation? encore une fois: n'hésitez pas à modifier mon message



2
votes

Le répertoire courant est, comme Victor l'a déjà souligné, dépendant de la commande utilisée pour lancer la JVM et donc dynamique à l'exécution. Vous avez besoin à la place d'un localisateur qui dépend de l'emplacement sur le fichier jar lui-même, ce qui signifie qu'il est dynamique au moment de la compilation mais statique au moment de l'exécution.

Il existe différentes approches ici, alors laissez-moi en présenter brièvement deux:

Utiliser un script de lancement

De cette façon, vous prenez simplement le contrôle de la ligne de commande vous-même, mais vous devez le faire pour chaque système d'exploitation où vous prévoyez d'utiliser votre programme. Sous Windows, cela pourrait ressembler à ceci:

app.bat:

P:\workspace\ConfigFile>dir deploy
...
02.05.2019  20:43             1.434 configFile.jar
02.05.2019  20:43                11 configFile.txt

P:\workspace\ConfigFile>java -jar deploy\configFile.jar
Hello World

Plus d'informations sur la première ligne ici .

Utiliser System ClassLoader
Cela fonctionne, car les sources du System ClassLoader sont dynamiques au moment de la compilation mais statiques au moment de l'exécution, donc exactement ce dont vous avez besoin. Cependant, cela présente l'inconvénient que vous ne pouvez pas écrire dans le fichier de configuration, car vous n'obtenez qu'un InputStream.

app.jar

Manifest-Version: 1.0
Class-Path: .
Main-Class: prv.izruo.test.ConfigFile


4 commentaires

Je préfère ne pas utiliser de script de démarrage, je choisis la deuxième approche. Mais je suis nul dans fXml


Au cas où je mettrais configFile.xml à l'intérieur du fichier jar, tout se passe bien. Comment demander au système d'obtenir des ressources non pas de jar, mais du même répertoire où se trouve le fichier jar?


Honnêtement, je n'en ai aucune idée. Aujourd'hui, j'ai revérifié mon projet au travail et composé un MCVE à la maison. Les deux sont parfaitement bien.


@vico Je pense que je l'ai trouvé en étudiant le Manifest de mon MCVE: vous devez ajouter . à votre classpath (ou à tout autre dossier dans lequel vous souhaitez enregistrer votre fichier de configuration).



2
votes

La meilleure façon pour vous de lire config.xml et d'autres ressources dont votre application pourrait avoir besoin est de les placer dans src / main / resources , puis de les référencer en tant que fichiers dans votre chemin de classe, comme ceci:

Shell

// ...

public static File getResourceAsFile(String resourcePath) {
    try {
        InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(resourcePath);
        if (in == null) {
            return null;
        }

        File tempFile = File.createTempFile(String.valueOf(in.hashCode()), ".tmp");
        tempFile.deleteOnExit();

        try (FileOutputStream out = new FileOutputStream(tempFile)) {
            //copy stream
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = in.read(buffer)) != -1) {
                out.write(buffer, 0, bytesRead);
            }
        }
        return tempFile;
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
}

File fXmlFile = getResourceAsFile("configFile.xml");

// ...

Code Java

mv configFile.xml /users/vico/my_program/src/main/resources

(ce code a été emprunté à cette réponse stackoverflow )

Ensuite, vous pouvez déplacer votre pot où vous voulez , envoyez-le même à vos utilisateurs et arrêtez de vous soucier de l'emplacement des fichiers de configuration.


0 commentaires