Czytaj plik właściwości poza plikiem JAR

132

Mam plik JAR, w którym cały mój kod jest archiwizowany do uruchomienia. Muszę uzyskać dostęp do pliku właściwości, który należy zmienić / edytować przed każdym uruchomieniem. Chcę zachować plik właściwości w tym samym katalogu, w którym znajduje się plik JAR. Czy w ogóle można powiedzieć Javie, aby pobrał plik właściwości z tego katalogu?

Uwaga: nie chcę przechowywać pliku właściwości w katalogu domowym ani przekazywać ścieżki do pliku właściwości w argumencie wiersza poleceń.

Neil
źródło
2
Zobacz tę odpowiedź - „Zamiast tego przechowuj„ domyślny ”plik w Słoiku. Jeśli zostanie zmieniony, zapisz zmieniony plik w innym miejscu. Jednym wspólnym miejscem jest podkatalog user.home. Podczas sprawdzania pliku najpierw sprawdź istnienie zmieniony plik w systemie plików, a jeśli nie istnieje, załaduj plik domyślny. " BTW „Nie chcę…” To, czego chcesz, jest mniej ważne niż to, co działa i jest praktyczne. Przechowywanie aplikacji. ustawienia w katalogu aplikacji są zdecydowanie odradzane zarówno przez Oracle, jak i MS (i prawdopodobnie inne).
Andrew Thompson,
3
Powodem, dla którego muszę przechowywać plik właściwości w katalogu jar, jest to, że lepiej przechowywać je razem, gdy cały katalog (w tym plik jar i właściwość) jest kopiowany na inny komputer i uruchamiany.
Neil
A jeśli zmuszę użytkownika do przekazania ścieżki do pliku właściwości, będzie musiał ją zmieniać za każdym razem, gdy uruchamia plik wsadowy z innej maszyny.
Neil

Odpowiedzi:

148

Tak więc chcesz traktować swój .propertiesplik w tym samym folderze co główny / uruchamialny plik jar, a nie jako zasób głównego / uruchamialnego pliku jar. W takim przypadku moje własne rozwiązanie wygląda następująco:

Po pierwsze: architektura pliku programu powinna wyglądać następująco (zakładając, że głównym programem jest main.jar, a jego głównym plikiem właściwości jest main.properties):

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

Dzięki tej architekturze można modyfikować dowolną właściwość w pliku main.properties za pomocą dowolnego edytora tekstu przed lub w trakcie działania pliku main.jar (w zależności od bieżącego stanu programu), ponieważ jest to tylko plik tekstowy. Na przykład plik main.properties może zawierać:

app.version=1.0.0.0
app.name=Hello

Tak więc, kiedy uruchamiasz swój główny program z jego katalogu głównego / podstawowego, zwykle uruchamiasz go w następujący sposób:

java -jar ./main.jar

lub od razu:

java -jar main.jar

W pliku main.jar musisz utworzyć kilka metod narzędziowych dla każdej właściwości znalezionej w pliku main.properties; powiedzmy, że app.versionwłaściwość będzie miała getAppVersion()następującą metodę:

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

W dowolnej części programu głównego, która potrzebuje app.versionwartości, wywołujemy jej metodę w następujący sposób:

String version = null;
try{
     version = getAppVersion();
}
catch (IOException ioe){
    ioe.printStackTrace();
}
ecle
źródło
7
To rozwiązanie działa. Dziękuję za zrozumienie dokładnych wymagań i szczegółowego kodu.Sprawdziłem, że plik właściwości nie znajduje się w pliku jar, ale nadal może uzyskać dostęp do pliku z tego samego katalogu, w którym znajduje się plik jar. W ten sposób nie jest wymagany stały kod ścieżki. Pliki jar i property można teraz kopiować do dowolnego katalogu i uruchamiać niezależnie.
Neil,
3
Plik nie zostanie znaleziony, jeśli wykonasz polecenie z zewnątrz, na przykład: {{java -jar build / main.jar}}. Czy masz na to jakieś rozwiązanie, @eee?
Darian,
@Darian Nie ma tu nic do naprawienia; Działa tylko zgodnie z projektem, w którym jar i plik właściwości muszą znajdować się w tym samym ./folderze głównym (na tym samym poziomie katalogu), co opisałem w architekturze organizacji plików. (zgodnie z wymogami oryginalnego plakatu)
ecle
@Darian, więc jeśli chcesz wykonać java -jar build/main.jar, musisz umieścić plik właściwości również w buildfolderze, aby znajdował się na tym samym poziomie katalogu co jar.
ecle
7
Dzięki za odpowiedź @eee, problem polega na tym, że nie wiem, gdzie użytkownik wykona plik java -jar path/to/jar/file. Ale znalazłem rozwiązanie w innym pytaniu:String path = ClassLoader.getSystemClassLoader().getResource(".").getPath() + "/main.properties";
Darian
45

Zrobiłem to w inny sposób.

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. Uzyskaj ścieżkę do pliku Jar.
  2. Pobierz folder nadrzędny tego pliku.
  3. Użyj tej ścieżki w InputStreamPath z nazwą pliku właściwości.
Ninad Pingale
źródło
Musiałem porzucić część getParentFile (), więc zamiast tego użyłem: String propertiesPath = jarPath.getAbsolutePath (); ale wszystko zależy od lokalizacji pliku
MobileMon,
4
Po prostu zastąp "jarPath.getParentFile (). GetAbsolutePath ();" do „jarPath.getParent ()”. Wtedy działa jak urok.
StackAddict
1
To samo dotyczy mojego przypadku, ale mam projekt podstawy sprężyny. Po czym poznać wiosnę, że plik jest obok pliku jar? jakikolwiek pomysł
Mubasher
3

Zawsze występuje problem z dostępem do plików w katalogu plików z pliku jar. Podanie ścieżki klas w pliku jar jest bardzo ograniczone. Zamiast tego spróbuj użyć pliku bat lub pliku sh, aby uruchomić program. W ten sposób możesz określić ścieżkę klasy tak, jak chcesz, odwołując się do dowolnego folderu w dowolnym miejscu w systemie.

Sprawdź także moją odpowiedź na to pytanie:

tworzenie pliku .exe dla projektu java zawierającego sqlite

sethu
źródło
1

Mam podobny przypadek: chcę, aby mój *.jarplik miał dostęp do pliku w katalogu obok wspomnianego *.jarpliku. Zapoznaj się również z TĄ ODPOWIEDZIĄ .

Moja struktura plików to:

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

Jestem w stanie załadować plik (powiedzmy some.txt) do InputStream wewnątrz *.jarpliku z następującymi elementami :

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

Następnie zrób, co chcesz, z stream

ddaaggeett
źródło
0

Mam przykład robienia obu przez classpath lub z zewnętrznej konfiguracji z 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
czarna smoła408
źródło
0

To działa dla mnie. Załaduj plik właściwości zcurrent 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);
        });

Upewnij się, że java.propertiesjest to current directory. Możesz po prostu napisać mały skrypt startowy, który przełączy się do odpowiedniego katalogu wcześniej, na przykład

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

W swoim projekcie po prostu umieść java.propertiesplik w katalogu głównym projektu, aby kod działał również z twojego IDE.

jschnasse
źródło
0

Tutaj, jeśli wspomnisz .getPath(), to zwróci ścieżkę do Jar i myślę, że będziesz potrzebować jego rodzica, aby odnosił się do wszystkich innych plików konfiguracyjnych umieszczonych w jar. Ten kod działa w systemie Windows. Dodaj kod w klasie głównej.

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

System.out.println(jarDirpath);
Sarangz
źródło