Прочитайте файл властивостей поза файлом JAR


131

У мене є файл JAR, де весь мій код архівується для запуску. Я маю доступ до файлу властивостей, який потрібно змінити / відредагувати перед кожним запуском. Я хочу зберегти файл властивостей у тому самому каталозі, де є файл JAR. Чи все-таки потрібно сказати Java забрати файл властивостей із цього каталогу?

Примітка: я не хочу зберігати файл властивостей у домашньому каталозі чи передавати шлях до файлу властивостей у аргументі командного рядка.


2
Дивіться цю відповідь - "Замість цього зберігайте файл" за замовчуванням "всередині Jar. Якщо він змінений, зберігайте змінений файл в іншому місці. Одне загальне місце - це підкаталог user.home. Перевіряючи файл, спочатку перевірте наявність змінений файл у файловій системі, і якщо його не існує, завантажте файл за замовчуванням. " BTW "Я не хочу .." Те, що ви хочете, є менш важливим, ніж те, що працює і є практичним. Зберігання програми. налаштування в каталозі додатків сильно перешкоджають Oracle та MS (і, можливо, іншими).
Ендрю Томпсон

3
Причина, чому мені потрібно зберігати файл властивостей у каталогу jar, полягає в тому, що краще зберігати їх разом, коли весь каталог (включаючи jar та властивість) скопійований на іншу машину та запущений.
Ніл

І якщо я змушую користувача пройти шлях до файла властивостей, то йому потрібно міняти його щоразу, коли він запускає пакетний файл з іншої машини.
Ніл

Відповіді:


144

Отже, ви хочете розглядати свій .propertiesфайл у тій же папці, що і основний / запущений jar, як файл, а не як ресурс основної / запущеної банки. У цьому випадку моє власне рішення полягає в наступному:

Перше, що спочатку: ваша архівація програмного файлу має бути такою (якщо припустимо, що ваша основна програма main.jar, а файл її основних властивостей main.properties):

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

За допомогою цієї архітектури ви можете змінювати будь-яке властивість у файлі main.properties, використовуючи будь-який текстовий редактор до або під час роботи вашого main.jar (залежно від поточного стану програми), оскільки це лише текстовий файл. Наприклад, ваш файл main.properties може містити:

app.version=1.0.0.0
app.name=Hello

Отже, коли ви запускаєте свою основну програму з кореневої / базової папки, зазвичай ви запускаєте її так:

java -jar ./main.jar

або, відразу:

java -jar main.jar

У своєму main.jar потрібно створити кілька утилітних методів для кожного ресурсу, знайденого у вашому файлі main.properties; скажімо, app.versionвластивість матиме getAppVersion()такий спосіб:

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

У будь-якій частині основної програми, яка потребує app.versionзначення, ми називаємо її метод таким чином:

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

7
Це рішення працює. Дякуємо, що зрозуміли точну вимогу та детальний код. Я перевірив, що файл властивостей не знаходиться у файлі jar, але все-таки він може отримати доступ до файлу з тієї самої директорії, де є файл jar. Таким чином не потрібен абсолютний жорсткий код шляху. І jar, і файл власності тепер можна скопіювати в будь-який каталог і запустити самостійно.
Ніл

3
Файл не буде знайдено, якщо виконувати команду ззовні для напр .: {{java -jar build / main.jar}}. У вас є якісь виправлення на це, @eee?
Даріан

@Darian Тут нічого не можна виправити; Він працює лише як розроблено там, де jar і файл властивостей повинні знаходитися в тій же ./кореневій папці (той самий рівень каталогу), що і те, що я описав в архітектурі організації файлів. (відповідно до вимог, встановлених оригінальним плакатом)
ecle

@Darian, тому якщо ви хочете виконати java -jar build/main.jar, вам потрібно також помістити файл властивостей у buildпапку, щоб він знаходився на тому ж рівні каталогу, що і jar.
ecle

7
Дякую за вашу відповідь @eee, проблема полягає в тому, що я не знаю, де користувач виконає java -jar path/to/jar/file. Але я знайшов рішення в іншому питанні:String path = ClassLoader.getSystemClassLoader().getResource(".").getPath() + "/main.properties";
Даріан

42

Я зробив це іншим способом.

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. Отримати шлях до файлу Jar.
  2. Отримайте батьківську папку цього файлу.
  3. Використовуйте цей шлях у InputStreamPath з назвою файлу властивостей.

Мені довелося скинути частину getParentFile (), тому замість цього я використав: String propertiesPath = jarPath.getAbsolutePath (); але все залежить від того, де знаходиться файл
MobileMon

4
Просто замініть "jarPath.getParentFile (). GetAbsolutePath ();" до "jarPath.getParent ()". Тоді як шарм працює.
StackAddict

1
Така ж проблема в моєму випадку, але у мене є проект весняної бази. Як сказати весною, що цей файл знаходиться поруч з файлом jar? будь-яка ідея
Mubasher

3

Завжди є проблема з доступом до файлів у вашому каталозі файлів із файлу jar. Надання класного шляху у файлі jar дуже обмежене. Натомість спробуйте використати файл bat або sh-файл для запуску програми. Таким чином ви можете вказувати свій класний шлях у будь-який спосіб, посилаючись на будь-яку папку в будь-якій точці системи.

Також перевірте мою відповідь на це питання:

створення .exe-файлу для java-проекту, що містить sqlite


1

У мене є подібний випадок: хочу, щоб мій *.jarфайл отримав доступ до файлу в каталозі поруч із вказаним *.jarфайлом. Також зверніться до цього ВІДПОВІДА .

Моя файлова структура:

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

Я можу завантажити файл (скажімо, some.txt) в InputStream всередині *.jarфайлу з наступним:

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

Тоді робіть все, що завгодно з вами stream


0

У мене є приклад виконання як через classpath, так і з зовнішнього конфігурації з 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

Це працює для мене. Завантажте файл з власностіcurrent 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);
        });

Переконайтеся, що java.propertiesце на current directory. Ви можете просто написати невеликий сценарій запуску, який переходить у потрібний каталог раніше, наприклад

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

У своєму проекті просто покладіть java.propertiesфайл у корінь свого проекту, щоб цей код працював і з вашого IDE.


0

Тут, якщо ви згадуєте .getPath()тоді, це поверне шлях Jar, і я думаю, вам знадобиться його батько для посилання на всі інші конфігураційні файли, розміщені в банку. Цей код працює в Windows. Додайте код в основний клас.

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

System.out.println(jarDirpath);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.