Прочитать файл свойств вне файла JAR

131

У меня есть файл JAR, в котором весь мой код заархивирован для запуска. Мне нужно получить доступ к файлу свойств, который необходимо изменить / отредактировать перед каждым запуском. Я хочу сохранить файл свойств в том же каталоге, где находится файл JAR. Есть ли способ сообщить Java, что нужно забрать файл свойств из этого каталога?

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

Нил
источник
2
См. Этот ответ - «Вместо этого сохраните файл по умолчанию внутри Jar. Если он был изменен, сохраните измененный файл в другом месте. Одним из распространенных мест является подкаталог user.home. При проверке файла сначала проверьте наличие измененный файл в файловой системе, и если он не существует, загрузить файл по умолчанию ». Кстати, «Я не хочу ..» То, что вы хотите, менее важно, чем то, что работает и практично. Хранение приложения. как Oracle, так и MS (и, возможно, другие) настоятельно не рекомендуют настройки в каталоге приложения.
Эндрю Томпсон
3
Причина, по которой мне нужно хранить файл свойств в каталоге jar, заключается в том, что лучше хранить их вместе, когда весь каталог (включая jar и свойство) копируется на другой компьютер и запускается.
Нил
И если я заставлю пользователя передать путь к файлу свойств, ему придется менять его каждый раз, когда он запускает командный файл с другого компьютера.
Нил

Ответы:

144

Итак, вы хотите обрабатывать свой .propertiesфайл в той же папке, что и основной / работающий jar, как файл, а не как ресурс основного / работающего 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();
}
ecle
источник
7
Это решение работает. Спасибо за понимание точных требований и подробный код. Я проверил, что файл свойств не находится внутри файла jar, но все же он может получить доступ к файлу из того же каталога, где находится файл jar. Таким образом, не требуется жесткий код абсолютного пути. И jar, и файл свойств теперь можно скопировать в любой каталог и запустить независимо.
Нил
3
Файл не будет найден, если вы выполните команду извне, например: {{java -jar build / main.jar}}. У тебя есть что-нибудь исправить, @eee?
Дариан
@Darian Здесь нечего поправлять; Он работает только так, как задумано, когда jar и файл свойств должны находиться в той же ./корневой папке (на том же уровне каталога), что и то, что я описал в архитектуре организации файлов. (в соответствии с требованиями оригинального плаката)
ecle
@Darian, поэтому, если вы хотите выполнить java -jar build/main.jar, вам нужно также поместить файл свойств в buildпапку, чтобы он находился на том же уровне каталога, что и jar.
ecle 09
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
То же самое в моем случае, но у меня есть весенний базовый проект. Как узнать Spring, что файл находится рядом с файлом jar? любая идея
Mubasher
3

Всегда есть проблема с доступом к файлам в вашем файловом каталоге из файла jar. Предоставление пути к классам в файле jar очень ограничено. Вместо этого попробуйте использовать файл bat или файл sh для запуска вашей программы. Таким образом, вы можете указать свой путь к классам в любом случае, ссылаясь на любую папку в любом месте системы.

Также проверьте мой ответ на этот вопрос:

создание файла .exe для проекта Java, содержащего sqlite

Sethu
источник
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

ddaaggeett
источник
0

У меня есть пример использования как пути к классам, так и внешней конфигурации с помощью 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
источник
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.

jschnasse
источник
0

Здесь, если вы упомянули .getPath(), это вернет путь к Jar, и я думаю, вам понадобится его родительский элемент, чтобы ссылаться на все другие файлы конфигурации, размещенные с jar. Этот код работает в Windows. Добавьте код в основной класс.

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

System.out.println(jarDirpath);
Sarangz
источник