Leer el archivo de propiedades fuera del archivo JAR

131

Tengo un archivo JAR donde se archiva todo mi código para su ejecución. Tengo que acceder a un archivo de propiedades que debe modificarse / editarse antes de cada ejecución. Quiero mantener el archivo de propiedades en el mismo directorio donde está el archivo JAR. ¿Hay alguna forma de decirle a Java que recoja el archivo de propiedades de ese directorio?

Nota: No quiero mantener el archivo de propiedades en el directorio de inicio ni pasar la ruta del archivo de propiedades en el argumento de la línea de comandos.

Neil
fuente
2
Vea esta respuesta : "En su lugar, guarde el archivo 'predeterminado' dentro del Jar. Si se modifica, guarde el archivo alterado en otro lugar. Un lugar común es un subdirectorio de user.home. Al verificar el archivo, primero verifique la existencia de un archivo alterado en el sistema de archivos y, si no existe, cargue el archivo predeterminado ". Por cierto "no quiero ..." Lo que quieres es menos importante que lo que funciona y es práctico. Aplicación de almacenamiento Oracle y MS (y probablemente otros) desaconsejan la configuración en el directorio de la aplicación.
Andrew Thompson
3
La razón por la que necesito mantener el archivo de propiedades en el directorio jar es que es mejor mantenerlos juntos cuando todo el directorio (incluidos jar y propiedad) se copia a otra máquina y se ejecuta.
Neil
Y si fuerzo al usuario a pasar la ruta del archivo de propiedades, entonces debe cambiarla cada vez que ejecuta el archivo por lotes desde una máquina diferente.
Neil

Respuestas:

144

Por lo tanto, desea tratar su .propertiesarchivo en la misma carpeta que el jar principal / ejecutable como un archivo en lugar de como un recurso del jar principal / ejecutable. En ese caso, mi propia solución es la siguiente:

Primero lo primero: la arquitectura del archivo de programa será así (suponiendo que su programa principal sea main.jar y su archivo de propiedades principal sea main.properties):

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

Con esta arquitectura, puede modificar cualquier propiedad en el archivo main.properties utilizando cualquier editor de texto antes o mientras se ejecuta su main.jar (dependiendo del estado actual del programa) ya que es solo un archivo basado en texto. Por ejemplo, su archivo main.properties puede contener:

app.version=1.0.0.0
app.name=Hello

Entonces, cuando ejecuta su programa principal desde su carpeta raíz / base, normalmente lo ejecutará así:

java -jar ./main.jar

o, de inmediato:

java -jar main.jar

En su main.jar, debe crear algunos métodos de utilidad para cada propiedad que se encuentre en su archivo main.properties; Digamos que la app.versionpropiedad tendrá el getAppVersion()método de la siguiente manera:

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

En cualquier parte del programa principal que necesita el app.versionvalor, llamamos a su método de la siguiente manera:

String version = null;
try{
     version = getAppVersion();
}
catch (IOException ioe){
    ioe.printStackTrace();
}
ecle
fuente
77
Esta solución funciona Gracias por entender el requisito exacto y el código detallado. Verifiqué que el archivo de propiedades no está dentro del archivo jar, pero aún así podría acceder al archivo desde el mismo directorio donde está el archivo jar. De esta manera, no se requiere una ruta absoluta de código duro. Tanto el archivo jar como el de propiedad ahora pueden copiarse a cualquier directorio y ejecutarse de manera independiente.
Neil
3
El archivo no se encontrará si ejecuta el comando desde afuera, por ejemplo: {{java -jar build / main.jar}}. ¿Tienes alguna solución para eso, @eee?
Darian
@Darian No hay nada que arreglar aquí; Solo funciona como está diseñado donde el archivo jar y las propiedades deben estar en la misma ./carpeta raíz (mismo nivel de directorio) que lo que he descrito en la arquitectura de la organización de archivos. (según el requisito establecido por el póster original)
ecle
@Darian, por lo que si desea ejecutar java -jar build/main.jar, también debe colocar el archivo de propiedades en la buildcarpeta para que esté en el mismo nivel de directorio que el jar.
ecle
77
Gracias por su respuesta @eee, el problema es que no sé dónde ejecutará el usuario java -jar path/to/jar/file. Pero encontré la solución en otra pregunta:String path = ClassLoader.getSystemClassLoader().getResource(".").getPath() + "/main.properties";
Darian
42

Lo hice de otra manera.

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. Obtener la ruta del archivo Jar.
  2. Obtener la carpeta principal de ese archivo.
  3. Use esa ruta en InputStreamPath con su nombre de archivo de propiedades.
Ninad Pingale
fuente
Tuve que soltar la parte getParentFile (), así que en su lugar usé: String propertiesPath = jarPath.getAbsolutePath (); pero todo depende de dónde esté ubicado el archivo
MobileMon
44
Simplemente reemplace "jarPath.getParentFile (). GetAbsolutePath ();" a "jarPath.getParent ()". Funciona como un encanto entonces.
StackAddict
1
El mismo es el problema en mi caso, pero tengo un proyecto base de primavera. ¿Cómo decirle a Spring que el archivo está al lado del archivo jar? alguna idea
Mubasher
3

Siempre hay un problema para acceder a los archivos en su directorio de archivos desde un archivo jar. Proporcionar el classpath en un archivo jar es muy limitado. En su lugar, intente usar un archivo bat o un archivo sh para iniciar su programa. De esa manera, puede especificar su classpath de la forma que desee, haciendo referencia a cualquier carpeta en cualquier parte del sistema.

Comprueba también mi respuesta a esta pregunta:

haciendo un archivo .exe para un proyecto java que contiene sqlite

sethu
fuente
1

Tengo un caso similar: querer que mi *.jararchivo acceda a un archivo en un directorio al lado de dicho *.jararchivo. Consulte esta RESPUESTA también.

Mi estructura de archivos es:

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

Puedo cargar un archivo (digamos some.txt) en un InputStream dentro del *.jararchivo con lo siguiente:

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

Luego haz lo que quieras con el stream

ddaaggeett
fuente
0

Tengo un ejemplo de hacer ambos por classpath o desde una configuración externa con 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
fuente
0

Esto funciona para mi. Cargue su archivo de propiedades desdecurrent 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);
        });

Asegúrate de que java.propertiesesté en el current directory. Simplemente puede escribir un pequeño script de inicio que cambie al directorio correcto antes, como

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

En su proyecto, simplemente coloque el java.propertiesarchivo en la raíz del proyecto, para que este código también funcione desde su IDE.

jschnasse
fuente
0

Aquí, si lo menciona .getPath(), devolverá la ruta de Jar y supongo que necesitará que su padre haga referencia a todos los demás archivos de configuración colocados con el jar. Este código funciona en Windows. Agregue el código dentro de la clase principal.

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

System.out.println(jarDirpath);
Sarangz
fuente