Ler arquivo de propriedades fora do arquivo JAR


131

Eu tenho um arquivo JAR no qual todo o meu código está arquivado para execução. Eu tenho que acessar um arquivo de propriedades que precisa ser alterado / editado antes de cada execução. Eu quero manter o arquivo de propriedades no mesmo diretório em que o arquivo JAR está. Existe alguma maneira de dizer ao Java para pegar o arquivo de propriedades desse diretório?

Nota: Não quero manter o arquivo de propriedades no diretório inicial nem passar o caminho do arquivo de propriedades no argumento da linha de comandos.


2
Veja esta resposta - "Em vez disso, armazene o arquivo 'padrão' dentro do Jar. Se ele for alterado, armazene o arquivo alterado em outro local. Um local comum é um subdiretório de user.home. Ao verificar o arquivo, verifique primeiro a existência de um arquivo alterado no sistema de arquivos e, se não existir, carregue o arquivo padrão ". BTW "Eu não quero .." O que você quer é menos importante do que aquilo que funciona e é prático. Armazenando aplicativo. as configurações no diretório do aplicativo são fortemente desencorajadas pelo Oracle e pelo MS (e provavelmente por outros).
Andrew Thompson

3
A razão pela qual eu preciso manter o arquivo de propriedades no diretório jar é que é melhor mantê-los juntos quando todo o diretório (incluindo jar e propriedade) é copiado para outra máquina e executado.
Neil

E se eu forçar o usuário a passar o caminho do arquivo de propriedades, ele precisará alterá-lo sempre que executar o arquivo em lotes de uma máquina diferente.
Neil

Respostas:


144

Portanto, você deseja tratar seu .propertiesarquivo na mesma pasta que o jar principal / executável como um arquivo, e não como um recurso do jar principal / executável. Nesse caso, minha própria solução é a seguinte:

Primeiro, a arquitetura do arquivo do programa deve ser assim (assumindo que o programa principal seja main.jar e seu arquivo de propriedades principal seja main.properties):

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

Com essa arquitetura, você pode modificar qualquer propriedade no arquivo main.properties usando qualquer editor de texto antes ou enquanto o main.jar estiver em execução (dependendo do estado atual do programa), pois é apenas um arquivo baseado em texto. Por exemplo, seu arquivo main.properties pode conter:

app.version=1.0.0.0
app.name=Hello

Portanto, quando você executa o programa principal a partir da pasta raiz / base, normalmente o executa da seguinte maneira:

java -jar ./main.jar

ou imediatamente:

java -jar main.jar

No seu main.jar, você precisa criar alguns métodos utilitários para todas as propriedades encontradas no seu arquivo main.properties; vamos dizer que a app.versionpropriedade terá o getAppVersion()método da seguinte maneira:

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

Em qualquer parte do programa principal que precise do app.versionvalor, chamamos seu método da seguinte maneira:

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

7
Esta solução funciona. Obrigado por entender o requisito exato e o código detalhado. Verifiquei que o arquivo de propriedades não está dentro do arquivo jar, mas ainda assim ele pode acessar o arquivo no mesmo diretório em que o arquivo jar está. Dessa maneira, não é necessário código rígido de caminho absoluto. Agora, os arquivos jar e property podem ser copiados para qualquer diretório e executados independentemente.
Neil

3
O arquivo não será encontrado se você executar o comando de fora para ex: {{java -jar build / main.jar}}. Você tem alguma solução para isso, @eee?
Darian

@ Darian Não há nada para consertar aqui; Ele funciona apenas conforme projetado onde o jar e o arquivo de propriedades devem estar na mesma ./pasta raiz (no mesmo nível de diretório) do que descrevi na arquitetura da organização do arquivo. (conforme o requisito definido pelo pôster original)
ecle

@ Darian, portanto, se você deseja executar java -jar build/main.jar, também precisa colocar o arquivo de propriedades na buildpasta, para que fique no mesmo nível de diretório que o jar.
ecle

7
Obrigado pela sua resposta @eee, o problema é que não sei onde o usuário executará o java -jar path/to/jar/file. Mas eu encontrei a solução em outra pergunta:String path = ClassLoader.getSystemClassLoader().getResource(".").getPath() + "/main.properties";
Darian

42

Eu fiz de outra maneira.

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. Obtenha o caminho do arquivo Jar.
  2. Obtenha a pasta pai desse arquivo.
  3. Use esse caminho no InputStreamPath com o nome do arquivo de propriedades.

Eu tive que largar a parte getParentFile (), então usei: String propertiesPath = jarPath.getAbsolutePath (); mas tudo depende de onde o arquivo está localizado
MobileMon

4
Apenas substitua "jarPath.getParentFile (). GetAbsolutePath ();" para "jarPath.getParent ()". Funciona como um encanto então.
StackAddict

1
O mesmo é o problema no meu caso, mas eu tenho o projeto base da primavera. Como saber se o arquivo está ao lado do arquivo jar? alguma idéia #
Mubasher

3

Sempre há um problema ao acessar arquivos no diretório de arquivos a partir de um arquivo jar. Fornecer o caminho de classe em um arquivo jar é muito limitado. Em vez disso, tente usar um arquivo bat ou um arquivo sh para iniciar seu programa. Dessa forma, você pode especificar seu caminho de classe da maneira que desejar, fazendo referência a qualquer pasta em qualquer lugar do sistema.

Verifique também minha resposta sobre esta pergunta:

criando arquivo .exe para projeto java contendo sqlite


1

Eu tenho um caso semelhante: querer que meu *.jararquivo acesse um arquivo em um diretório próximo ao *.jararquivo. Consulte ESTA RESPOSTA também.

Minha estrutura de arquivos é:

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

Consigo carregar um arquivo (digamos some.txt) para um InputStream dentro do *.jararquivo com o seguinte:

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

Então faça o que quiser com o stream


0

Eu tenho um exemplo de fazer tanto por caminho de classe ou de configuração externa com 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

Isso funciona para mim. Carregue seu arquivo de propriedades decurrent 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);
        });

Certifique-se de que java.propertiesestá no current directory. Você pode escrever um pequeno script de inicialização que muda para o diretório certo antes, como

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

No seu projeto, basta colocar o java.propertiesarquivo na raiz do projeto, para que esse código funcione também no seu IDE.


0

Aqui, se você mencionar .getPath(), isso retornará o caminho do Jar e acho que você precisará do pai para se referir a todos os outros arquivos de configuração colocados no jar. Este código funciona no Windows. Adicione o código na classe principal.

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

System.out.println(jarDirpath);
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.