Lire le fichier de propriétés en dehors du fichier JAR

131

J'ai un fichier JAR où tout mon code est archivé pour être exécuté. Je dois accéder à un fichier de propriétés qui doit être changé / édité avant chaque exécution. Je souhaite conserver le fichier de propriétés dans le même répertoire que celui où se trouve le fichier JAR. Est-il possible de dire à Java de récupérer le fichier de propriétés dans ce répertoire?

Remarque: je ne souhaite pas conserver le fichier de propriétés dans le répertoire personnel ou transmettre le chemin du fichier de propriétés en argument de ligne de commande.

Neil
la source
2
Voir cette réponse - "Stockez plutôt le fichier 'par défaut' dans le Jar. S'il est modifié, stockez le fichier modifié à un autre endroit. Un emplacement commun est un sous-répertoire de user.home. Lors de la vérification du fichier, vérifiez d'abord l'existence de un fichier modifié sur le système de fichiers, et s'il n'existe pas, chargez le fichier par défaut. " BTW "Je ne veux pas .." Ce que vous voulez est moins important que ce qui fonctionne et est pratique. Stockage de l'application. Les paramètres dans le répertoire de l'application sont fortement déconseillés par Oracle et MS (et probablement d'autres).
Andrew Thompson
3
La raison pour laquelle je dois conserver le fichier de propriétés dans le répertoire jar est qu'il est préférable de les garder ensemble lorsque le répertoire entier (y compris le fichier jar et la propriété) est copié sur une autre machine et exécuté.
Neil
Et si je force l'utilisateur à transmettre le chemin du fichier de propriétés, il doit le changer chaque fois qu'il exécute le fichier de commandes à partir d'une machine différente.
Neil

Réponses:

144

Alors, vous voulez traiter votre .properties fichier dans le même dossier que le fichier jar principal / exécutable comme un fichier plutôt que comme une ressource du fichier jar principal / exécutable. Dans ce cas, ma propre solution est la suivante:

Tout d'abord, l'architecture de votre fichier programme doit être comme ceci (en supposant que votre programme principal est main.jar et que son fichier de propriétés principal est main.properties):

./ - the root of your program
 |__ main.jar
 |__ main.properties

Avec cette architecture, vous pouvez modifier n'importe quelle propriété du fichier main.properties à l'aide de n'importe quel éditeur de texte avant ou pendant l'exécution de votre main.jar (selon l'état actuel du programme) car il ne s'agit que d'un fichier texte. Par exemple, votre fichier main.properties peut contenir:

app.version=1.0.0.0
app.name=Hello

Ainsi, lorsque vous exécutez votre programme principal à partir de son dossier racine / de base, vous l'exécuterez normalement comme ceci:

java -jar ./main.jar

ou, tout de suite:

java -jar main.jar

Dans votre main.jar, vous devez créer quelques méthodes utilitaires pour chaque propriété trouvée dans votre fichier main.properties; disons que la app.versionpropriété aura la getAppVersion()méthode suivante:

/**
 * Gets the app.version property value from
 * the ./main.properties file of the base folder
 *
 * @return app.version string
 * @throws IOException
 */

import java.util.Properties;

public static String getAppVersion() throws IOException{

    String versionString = null;

    //to load application's properties, we use this class
    Properties mainProperties = new Properties();

    FileInputStream file;

    //the base folder is ./, the root of the main.properties file  
    String path = "./main.properties";

    //load the file handle for main.properties
    file = new FileInputStream(path);

    //load all the properties from this file
    mainProperties.load(file);

    //we have loaded the properties, so close the file handle
    file.close();

    //retrieve the property we are intrested, the app.version
    versionString = mainProperties.getProperty("app.version");

    return versionString;
}

Dans toute partie du programme principal qui a besoin de la app.versionvaleur, nous appelons sa méthode comme suit:

String version = null;
try{
     version = getAppVersion();
}
catch (IOException ioe){
    ioe.printStackTrace();
}
ecle
la source
7
Cette solution fonctionne. Merci d'avoir compris l'exigence exacte et le code détaillé.J'ai vérifié que le fichier de propriétés ne se trouvait pas dans le fichier jar mais qu'il pouvait toujours accéder au fichier à partir du même répertoire que le fichier jar. De cette manière, aucun code de chemin absolu n'est requis. Le fichier jar et le fichier de propriétés peuvent désormais être copiés dans n'importe quel répertoire et exécutés indépendamment.
Neil
3
Le fichier ne sera pas trouvé si vous exécutez la commande de l'extérieur par exemple: {{java -jar build / main.jar}}. Avez-vous une solution à cela, @eee?
Darian
@Darian Il n'y a rien à réparer ici; Cela fonctionne uniquement comme prévu lorsque le fichier jar et le fichier de propriétés doivent être sur le même ./dossier racine (même niveau de répertoire) que ce que j'ai décrit dans l'architecture d'organisation des fichiers. (selon les exigences fixées par l'affiche originale)
ecle
@Darian, donc si vous voulez exécuter java -jar build/main.jar, vous devez également placer le fichier de propriétés dans le builddossier afin qu'il soit au même niveau de répertoire que le fichier jar.
ecle le
7
Merci pour votre réponse @eee, le problème est que je ne sais pas où l'utilisateur exécutera le fichier java -jar path/to/jar/file. Mais j'ai trouvé la solution dans une autre question:String path = ClassLoader.getSystemClassLoader().getResource(".").getPath() + "/main.properties";
Darian
42

Je l'ai fait autrement.

Properties prop = new Properties();
    try {

        File jarPath=new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().getPath());
        String propertiesPath=jarPath.getParentFile().getAbsolutePath();
        System.out.println(" propertiesPath-"+propertiesPath);
        prop.load(new FileInputStream(propertiesPath+"/importer.properties"));
    } catch (IOException e1) {
        e1.printStackTrace();
    }
  1. Obtenez le chemin du fichier Jar.
  2. Obtenez le dossier Parent de ce fichier.
  3. Utilisez ce chemin dans InputStreamPath avec le nom de votre fichier de propriétés.
Ninad Pingale
la source
J'ai dû supprimer la partie getParentFile (), alors j'ai utilisé à la place: String propertiesPath = jarPath.getAbsolutePath (); mais tout dépend de l'emplacement du fichier
MobileMon
4
Remplacez simplement "jarPath.getParentFile (). GetAbsolutePath ();" à "jarPath.getParent ()". Fonctionne comme un charme alors.
StackAddict
1
C'est le même problème dans mon cas, mais j'ai un projet de base à ressort. Comment dire au printemps que le fichier est à côté du fichier jar? toute idée
Mubasher
3

Il y a toujours un problème pour accéder aux fichiers de votre répertoire de fichiers à partir d'un fichier jar. Fournir le classpath dans un fichier jar est très limité. Essayez plutôt d'utiliser un fichier bat ou un fichier sh pour démarrer votre programme. De cette façon, vous pouvez spécifier votre chemin de classe comme vous le souhaitez, en référençant n'importe quel dossier n'importe où sur le système.

Vérifiez également ma réponse à cette question:

création d'un fichier .exe pour un projet java contenant sqlite

Sethu
la source
1

J'ai un cas similaire: vouloir que mon *.jarfichier accède à un fichier dans un répertoire à côté dudit *.jarfichier. Reportez-vous également à CETTE RÉPONSE .

Ma structure de fichiers est:

./ - the root of your program
|__ *.jar
|__ dir-next-to-jar/some.txt

Je suis capable de charger un fichier (par exemple some.txt) dans un InputStream à l'intérieur du *.jarfichier avec les éléments suivants:

InputStream stream = null;
    try{
        stream = ThisClassName.class.getClass().getResourceAsStream("/dir-next-to-jar/some.txt");
    }
    catch(Exception e) {
        System.out.print("error file to stream: ");
        System.out.println(e.getMessage());
    }

Alors fais ce que tu veux avec le stream

ddaaggeett
la source
0

J'ai un exemple de faire à la fois par classpath ou à partir d'une configuration externe avec log4j2.properties

package org.mmartin.app1;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.LogManager;


public class App1 {
    private static Logger logger=null; 
    private static final String LOG_PROPERTIES_FILE = "config/log4j2.properties";
    private static final String  CONFIG_PROPERTIES_FILE = "config/config.properties";

    private Properties properties= new Properties();

    public App1() {
        System.out.println("--Logger intialized with classpath properties file--");
        intializeLogger1();
        testLogging();
        System.out.println("--Logger intialized with external file--");
        intializeLogger2();
        testLogging();
    }




    public void readProperties()  {
        InputStream input = null;
        try {
            input = new FileInputStream(CONFIG_PROPERTIES_FILE);
            this.properties.load(input);
        } catch (IOException e) {
            logger.error("Unable to read the config.properties file.",e);
            System.exit(1);
        }
    }

    public void printProperties() {
        this.properties.list(System.out);
    }

    public void testLogging() {
        logger.debug("This is a debug message");
        logger.info("This is an info message");
        logger.warn("This is a warn message");
        logger.error("This is an error message");
        logger.fatal("This is a fatal message");
        logger.info("Logger's name: "+logger.getName());
    }


    private void intializeLogger1() {
        logger = LogManager.getLogger(App1.class);
    }
    private void intializeLogger2() {
        LoggerContext context = (org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false);
        File file = new File(LOG_PROPERTIES_FILE);
        // this will force a reconfiguration
        context.setConfigLocation(file.toURI());
        logger = context.getLogger(App1.class.getName());
    }

    public static void main(String[] args) {
        App1 app1 = new App1();
        app1.readProperties();
        app1.printProperties();
    }
}


--Logger intialized with classpath properties file--
[DEBUG] 2018-08-27 10:35:14.510 [main] App1 - This is a debug message
[INFO ] 2018-08-27 10:35:14.513 [main] App1 - This is an info message
[WARN ] 2018-08-27 10:35:14.513 [main] App1 - This is a warn message
[ERROR] 2018-08-27 10:35:14.513 [main] App1 - This is an error message
[FATAL] 2018-08-27 10:35:14.513 [main] App1 - This is a fatal message
[INFO ] 2018-08-27 10:35:14.514 [main] App1 - Logger's name: org.mmartin.app1.App1
--Logger intialized with external file--
[DEBUG] 2018-08-27 10:35:14.524 [main] App1 - This is a debug message
[INFO ] 2018-08-27 10:35:14.525 [main] App1 - This is an info message
[WARN ] 2018-08-27 10:35:14.525 [main] App1 - This is a warn message
[ERROR] 2018-08-27 10:35:14.525 [main] App1 - This is an error message
[FATAL] 2018-08-27 10:35:14.525 [main] App1 - This is a fatal message
[INFO ] 2018-08-27 10:35:14.525 [main] App1 - Logger's name: org.mmartin.app1.App1
-- listing properties --
dbpassword=password
database=localhost
dbuser=user
pitchblack408
la source
0

Cela fonctionne pour moi. Chargez votre fichier de propriétés depuiscurrent directory

Properties properties = new Properties();
properties.load(new FileReader(new File(".").getCanonicalPath() + File.separator + "java.properties"));
properties.forEach((k, v) -> {
            System.out.println(k + " : " + v);
        });

Assurez-vous que java.propertiesc'est au current directory. Vous pouvez simplement écrire un petit script de démarrage qui bascule dans le bon répertoire avant, comme

#! /bin/bash
scriptdir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 
cd $scriptdir
java -jar MyExecutable.jar
cd -

Dans votre projet, placez simplement le java.propertiesfichier dans la racine de votre projet, afin que ce code fonctionne également à partir de votre IDE.

jschnasse
la source
0

Ici, si vous mentionnez, .getPath()cela renverra le chemin de Jar et je suppose que vous aurez besoin de son parent pour faire référence à tous les autres fichiers de configuration placés avec le jar. Ce code fonctionne sous Windows. Ajoutez le code dans la classe principale.

File jarDir = new File(MyAppName.class.getProtectionDomain().getCodeSource().getLocation().getPath());
String jarDirpath = jarDir.getParent();

System.out.println(jarDirpath);
Sarangz
la source