Leggi il file delle proprietà all'esterno del file JAR


131

Ho un file JAR in cui tutto il mio codice è archiviato per l'esecuzione. Devo accedere a un file delle proprietà che deve essere modificato / modificato prima di ogni esecuzione. Voglio mantenere il file delle proprietà nella stessa directory in cui si trova il file JAR. Esiste un modo per dire a Java di prelevare il file delle proprietà da quella directory?

Nota: non voglio mantenere il file delle proprietà nella home directory o passare il percorso del file delle proprietà nell'argomento della riga di comando.


2
Vedi questa risposta - "Invece archivia il file 'default' all'interno del Jar. Se è cambiato, archivia il file modificato in un altro posto. Un posto comune è una sotto-directory di user.home. Quando controlli il file, controlla prima l'esistenza di un file modificato sul file system e, se non esiste, caricare il file predefinito. " A proposito "Non voglio .." Quello che vuoi è meno importante di ciò che funziona ed è pratico. App di archiviazione. le impostazioni nella directory dell'applicazione sono fortemente scoraggiate da Oracle e MS (e probabilmente da altri).
Andrew Thompson,

3
Il motivo per cui ho bisogno di mantenere il file delle proprietà nella directory jar è che è meglio tenerli insieme quando l'intera directory (compresi jar e proprietà) viene copiata su un'altra macchina ed eseguita.
Neil

E se costringo l'utente a passare il percorso del file delle proprietà, deve cambiarlo ogni volta che esegue il file batch da una macchina diversa.
Neil

Risposte:


144

Quindi, vuoi trattare il tuo .propertiesfile nella stessa cartella del barattolo principale / eseguibile come un file piuttosto che come una risorsa del barattolo principale / eseguibile. In tal caso, la mia soluzione è la seguente:

Prima cosa: l'architettura del file di programma deve essere così (supponendo che il tuo programma principale sia main.jar e il suo file delle proprietà principale sia main.properties):

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

Con questa architettura, è possibile modificare qualsiasi proprietà nel file main.properties utilizzando qualsiasi editor di testo prima o mentre main.jar è in esecuzione (a seconda dello stato corrente del programma) poiché è solo un file di testo. Ad esempio, il file main.properties può contenere:

app.version=1.0.0.0
app.name=Hello

Quindi, quando esegui il tuo programma principale dalla sua cartella root / base, normalmente lo eseguirai così:

java -jar ./main.jar

o, subito:

java -jar main.jar

Nel tuo main.jar, devi creare alcuni metodi di utilità per ogni proprietà trovata nel tuo file main.properties; diciamo che la app.versionproprietà avrà il getAppVersion()metodo come segue:

/**
 * 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;
}

In qualsiasi parte del programma principale che necessita del app.versionvalore, chiamiamo il suo metodo come segue:

String version = null;
try{
     version = getAppVersion();
}
catch (IOException ioe){
    ioe.printStackTrace();
}

7
Questa soluzione funziona. Grazie per la comprensione del requisito esatto e del codice dettagliato. Ho verificato che il file delle proprietà non si trova all'interno del file jar, ma potrebbe comunque accedere al file dalla stessa directory in cui si trova il file jar. In questo modo non è richiesto il codice hard percorso assoluto. Sia il file jar che il file delle proprietà ora possono essere copiati in qualsiasi directory ed eseguiti in modo indipendente.
Neil

3
Il file non verrà trovato se si esegue il comando dall'esterno per es: {{java -jar build / main.jar}}. Hai qualche soluzione per questo, @eee?
Darian,

@Darian Non c'è niente da risolvere qui; Funziona solo come progettato in cui il vaso e il file delle proprietà devono trovarsi nella stessa ./cartella principale (stesso livello di directory) rispetto a quanto descritto nell'architettura dell'organizzazione dei file. (come da requisito stabilito dal poster originale)
ecle

@Darian, quindi se si desidera eseguire java -jar build/main.jar, è necessario inserire anche il file delle proprietà nella buildcartella in modo che si trovi sullo stesso livello di directory del jar.
ecle,

7
Grazie per la tua risposta @eee, il problema è che non so dove l'utente eseguirà il java -jar path/to/jar/file. Ma ho trovato la soluzione in un'altra domanda:String path = ClassLoader.getSystemClassLoader().getResource(".").getPath() + "/main.properties";
Darian,

42

L'ho fatto in altro modo.

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. Ottieni il percorso del file Jar.
  2. Ottieni la cartella principale di quel file.
  3. Utilizzare quel percorso in InputStreamPath con il nome del file delle proprietà.

Ho dovuto eliminare la parte getParentFile (), quindi invece ho usato: String propertiesPath = jarPath.getAbsolutePath (); ma tutto dipende da dove si trova il file
MobileMon,

4
Sostituisci semplicemente "jarPath.getParentFile (). GetAbsolutePath ();" a "jarPath.getParent ()". Funziona come un incantesimo allora.
StackAddict

1
Lo stesso è il problema nel mio caso, ma ho un progetto di base di primavera. Come dire a primavera che il file si trova accanto al file jar? qualsiasi idea
Mubasher,

3

C'è sempre un problema ad accedere ai file nella directory dei file da un file jar. Fornire il percorso di classe in un file jar è molto limitato. Prova invece a utilizzare un file bat o un file sh per avviare il programma. In questo modo puoi specificare il tuo percorso di classe come preferisci, facendo riferimento a qualsiasi cartella in qualsiasi punto del sistema.

Controlla anche la mia risposta a questa domanda:

creazione di file .exe per progetti java contenenti sqlite


1

Ho un caso simile: volevo che il mio *.jarfile accedesse a un file in una directory accanto a detto *.jarfile. Consultare anche QUESTA RISPOSTA .

La mia struttura dei file è:

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

Sono in grado di caricare un file (diciamo, some.txt) in un InputStream all'interno del *.jarfile con il seguente:

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

Quindi fai quello che vuoi con il stream


0

Ho un esempio di fare sia da classpath o da configurazione esterna con 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

0

Questo funziona per me. Carica il tuo file delle proprietà dacurrent 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);
        });

Assicurati che java.propertiessia al current directory. Puoi semplicemente scrivere un piccolo script di avvio che passa alla directory giusta in precedenza, come

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

Nel tuo progetto basta inserire il java.propertiesfile nella radice del progetto, in modo da far funzionare questo codice anche dal tuo IDE.


0

Qui, se menzioni, .getPath()ciò restituirà il percorso di Jar e immagino che avrai bisogno del suo genitore per fare riferimento a tutti gli altri file di configurazione posizionati con il jar. Questo codice funziona su Windows. Aggiungi il codice all'interno della classe principale.

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

System.out.println(jarDirpath);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.