Lesen Sie die Eigenschaftendatei außerhalb der JAR-Datei

131

Ich habe eine JAR-Datei, in der mein gesamter Code zum Ausführen archiviert wird. Ich muss auf eine Eigenschaftendatei zugreifen, die vor jedem Lauf geändert / bearbeitet werden muss. Ich möchte die Eigenschaftendatei in demselben Verzeichnis behalten, in dem sich die JAR-Datei befindet. Gibt es eine Möglichkeit, Java anzuweisen, die Eigenschaftendatei aus diesem Verzeichnis abzurufen?

Hinweis: Ich möchte die Eigenschaftendatei nicht im Ausgangsverzeichnis behalten oder den Pfad der Eigenschaftendatei im Befehlszeilenargument übergeben.

Neil
quelle
2
Siehe diese Antwort - "Speichern Sie stattdessen die 'Standard'-Datei im Jar. Wenn sie geändert wird, speichern Sie die geänderte Datei an einem anderen Ort. Ein häufiger Ort ist ein Unterverzeichnis von user.home. Wenn Sie nach der Datei suchen, überprüfen Sie zuerst die Existenz von eine geänderte Datei im Dateisystem, und wenn sie nicht vorhanden ist, laden Sie die Standarddatei. " Übrigens "Ich will nicht ..." Was Sie wollen, ist weniger wichtig als das, was funktioniert und praktisch ist. App speichern. Von den Einstellungen im Anwendungsverzeichnis wird sowohl von Oracle als auch von MS (und wahrscheinlich auch von anderen) dringend abgeraten.
Andrew Thompson
3
Der Grund, warum ich die Eigenschaftendatei im JAR-Verzeichnis behalten muss, ist, dass es besser ist, sie zusammen zu halten, wenn das gesamte Verzeichnis (einschließlich JAR und Eigenschaft) auf einen anderen Computer kopiert und ausgeführt wird.
Neil
Und wenn ich den Benutzer zwinge, den Pfad der Eigenschaftendatei zu übergeben, muss er ihn jedes Mal ändern, wenn er die Batchdatei von einem anderen Computer aus ausführt.
Neil

Antworten:

144

Sie möchten Ihre .propertiesDatei also im selben Ordner wie das Haupt- / ausführbare JAR als Datei und nicht als Ressource des Haupt- / ausführbaren JARs behandeln. In diesem Fall lautet meine eigene Lösung wie folgt:

Das erste zuerst: Ihre Programmdatei-Architektur muss so aussehen (vorausgesetzt, Ihr Hauptprogramm ist main.jar und seine Haupteigenschaftendatei ist main.properties):

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

Mit dieser Architektur können Sie jede Eigenschaft in der Datei main.properties mit einem beliebigen Texteditor ändern, bevor oder während Ihre main.jar ausgeführt wird (abhängig vom aktuellen Status des Programms), da es sich nur um eine textbasierte Datei handelt. Beispielsweise kann Ihre Datei main.properties Folgendes enthalten:

app.version=1.0.0.0
app.name=Hello

Wenn Sie also Ihr Hauptprogramm aus dem Stamm- / Basisordner ausführen, führen Sie es normalerweise folgendermaßen aus:

java -jar ./main.jar

oder sofort:

java -jar main.jar

In Ihrer Datei main.jar müssen Sie für jede Eigenschaft in Ihrer Datei main.properties einige Dienstprogrammmethoden erstellen. sagen wir dasapp.version Eigenschaft hat folgende getAppVersion()Methode:

/**
 * 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 jedem Teil des Hauptprogramms, der den app.versionWert benötigt, rufen wir seine Methode wie folgt auf:

String version = null;
try{
     version = getAppVersion();
}
catch (IOException ioe){
    ioe.printStackTrace();
}
ecle
quelle
7
Diese Lösung funktioniert. Vielen Dank für das Verständnis der genauen Anforderungen und des detaillierten Codes. Ich habe überprüft, dass sich die Eigenschaftendatei nicht in der JAR-Datei befindet, aber dennoch aus demselben Verzeichnis auf die Datei zugreifen kann, in dem sich die JAR-Datei befindet. Auf diese Weise ist kein absoluter Pfad-Hardcode erforderlich. Sowohl die JAR- als auch die Eigenschaftendatei können jetzt in ein beliebiges Verzeichnis kopiert und unabhängig voneinander ausgeführt werden.
Neil
3
Die Datei wird nicht gefunden, wenn Sie den Befehl von außen ausführen, z. B. {{java -jar build / main.jar}}. Hast du eine Lösung dafür, @eee?
Darian
@Darian Hier gibt es nichts zu reparieren; Es funktioniert nur so, wie es entworfen wurde, wenn sich die JAR- und die Eigenschaftendatei im selben ./Stammordner (auf derselben Verzeichnisebene) befinden müssen, wie ich es in der Architektur der Dateiorganisation beschrieben habe. (gemäß den Anforderungen des Originalplakats)
Ecle
@Darian Wenn Sie also ausführen möchten, java -jar build/main.jarmüssen Sie die Eigenschaftendatei ebenfalls in einem buildOrdner ablegen, damit sie sich auf derselben Verzeichnisebene wie das JAR befindet.
Ecle
7
Vielen Dank für Ihre Antwort @eee, das Problem ist, ich weiß nicht, wo Benutzer das ausführen wird java -jar path/to/jar/file. Aber ich fand die Lösung in einer anderen Frage:String path = ClassLoader.getSystemClassLoader().getResource(".").getPath() + "/main.properties";
Darian
42

Ich habe es anders gemacht.

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. Holen Sie sich den Jar-Dateipfad.
  2. Holen Sie sich den übergeordneten Ordner dieser Datei.
  3. Verwenden Sie diesen Pfad in InputStreamPath mit dem Namen Ihrer Eigenschaftendatei.
Ninad Pingale
quelle
Ich musste den Teil getParentFile () löschen, also verwendete ich stattdessen: String propertiesPath = jarPath.getAbsolutePath (); Aber es hängt alles davon ab, wo sich die Datei befindet
MobileMon
4
Ersetzen Sie einfach "jarPath.getParentFile (). GetAbsolutePath ();" zu "jarPath.getParent ()". Funktioniert dann wie ein Zauber.
StackAddict
1
Das gleiche ist das Problem in meinem Fall, aber ich habe ein Federbasisprojekt. Wie kann man Spring sagen, dass sich die Datei neben der JAR-Datei befindet? jede Idee
Mubasher
3

Es gibt immer ein Problem beim Zugriff auf Dateien in Ihrem Dateiverzeichnis aus einer JAR-Datei. Das Bereitstellen des Klassenpfads in einer JAR-Datei ist sehr begrenzt. Versuchen Sie stattdessen, eine Bat-Datei oder eine Sh-Datei zu verwenden, um Ihr Programm zu starten. Auf diese Weise können Sie Ihren Klassenpfad beliebig angeben und auf einen beliebigen Ordner im gesamten System verweisen.

Überprüfen Sie auch meine Antwort auf diese Frage:

Erstellen einer EXE-Datei für ein Java-Projekt, das SQLite enthält

Sethu
quelle
1

Ich habe einen ähnlichen Fall: Ich möchte, dass meine *.jarDatei auf eine Datei in einem Verzeichnis neben dieser *.jarDatei zugreift. Siehe DIESE ANTWORT .

Meine Dateistruktur ist:

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

Ich kann eine Datei (z. B. some.txt) in einen InputStream in der *.jarDatei wie folgt laden :

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

Dann mach was du willst mit dem stream

ddaaggeett
quelle
0

Ich habe ein Beispiel dafür, wie man sowohl mit dem Klassenpfad als auch mit der externen Konfiguration mit log4j2.properties arbeitet

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
quelle
0

Das funktioniert bei mir. Laden Sie Ihre Eigenschaftendatei voncurrent 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);
        });

Stellen Sie sicher, das java.propertiesist am current directory. Sie können einfach ein kleines Startskript schreiben, das zuvor in das richtige Verzeichnis wechselt

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

java.propertiesFügen Sie in Ihrem Projekt die Datei einfach in Ihr Projektstammverzeichnis ein, damit dieser Code auch in Ihrer IDE funktioniert.

jschnasse
quelle
0

Wenn Sie hier erwähnen .getPath(), wird der Pfad von Jar zurückgegeben, und ich denke, Sie benötigen das übergeordnete Element, um auf alle anderen Konfigurationsdateien zu verweisen, die im Jar abgelegt sind. Dieser Code funktioniert unter Windows. Fügen Sie den Code innerhalb der Hauptklasse hinzu.

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

System.out.println(jarDirpath);
Sarangz
quelle