Read properties file outside JAR file

JavaProperties

Java Problem Overview


I have a JAR file where all my code is archived for running. I have to access a properties file which need to be changed/edited before each run. I want to keep the properties file in the same directory where the JAR file is. Is there anyway to tell Java to pick up the properties file from that directory ?

Note: I do not want to keep the properties file in home directory or pass the path of the properties file in command line argument.

Java Solutions


Solution 1 - Java

So, you want to treat your .properties file on the same folder as the main/runnable jar as a file rather than as a resource of the main/runnable jar. In that case, my own solution is as follows:

First thing first: your program file architecture shall be like this (assuming your main program is main.jar and its main properties file is main.properties):

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

With this architecture, you can modify any property in the main.properties file using any text editor before or while your main.jar is running (depending on the current state of the program) since it is just a text-based file. For example, your main.properties file may contain:

app.version=1.0.0.0
app.name=Hello

So, when you run your main program from its root/base folder, normally you will run it like this:

java -jar ./main.jar

or, straight away:

java -jar main.jar

In your main.jar, you need to create a few utility methods for every property found in your main.properties file; let say the app.version property will have getAppVersion() method as follows:

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

In any part of the main program that needs the app.version value, we call its method as follows:

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

Solution 2 - Java

I did it by other way.

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. Get Jar file path.
  2. Get Parent folder of that file.
  3. Use that path in InputStreamPath with your properties file name.

Solution 3 - Java

There's always a problem accessing files on your file directory from a jar file. Providing the classpath in a jar file is very limited. Instead try using a bat file or a sh file to start your program. In that way you can specify your classpath anyway you like, referencing any folder anywhere on the system.

Also check my answer on this question:

https://stackoverflow.com/questions/8774546/making-exe-file-for-java-project-containing-sqlite/8775042#comment10940685_8775042

Solution 4 - Java

I have a similar case: wanting my *.jar file to access a file in a directory next to said *.jar file. Refer to THIS ANSWER as well.

My file structure is:

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

I'm able to load a file (say, some.txt) to an InputStream inside the *.jar file with the following:

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

Then do whatever you will with the stream

Solution 5 - Java

This works for me. Load your properties file from current directory.

Attention: The method Properties#load uses ISO-8859-1 encoding.

Properties properties = new Properties();
properties.load(new FileReader(new File(".").getCanonicalPath() + File.separator + "java.properties"));
properties.forEach((k, v) -> {
			System.out.println(k + " : " + v);
		});

Make sure, that java.properties is at the current directory . You can just write a little startup script that switches into to the right directory in before, like

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

In your project just put the java.properties file in your project root, in order to make this code work from your IDE as well.

Solution 6 - Java

I have an example of doing both by classpath or from external config with 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

Solution 7 - Java

Here if you mention .getPath() then that will return the path of Jar and I guess you will need its parent to refer to all other config files placed with the jar. This code works on Windows. Add the code within the main class.

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

System.out.println(jarDirpath);

Solution 8 - Java

File parentFile = new File(".");
String parentPath = file.getCanonicalPath();
File resourceFile = new File(parentPath+File.seperator+"<your config file>");

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNeilView Question on Stackoverflow
Solution 1 - JavaecleView Answer on Stackoverflow
Solution 2 - JavaNinad PingaleView Answer on Stackoverflow
Solution 3 - JavasethuView Answer on Stackoverflow
Solution 4 - JavaddaaggeettView Answer on Stackoverflow
Solution 5 - JavajschnasseView Answer on Stackoverflow
Solution 6 - Javapitchblack408View Answer on Stackoverflow
Solution 7 - JavaSarangzView Answer on Stackoverflow
Solution 8 - JavaJay devView Answer on Stackoverflow