2

I am making a program that works with MySQL database,for now i store URL, login, password e.t.c as public static String. Now i need to make it possible to work on another computer, so database adress will vary, so i need a way to edit it inside programm and save. I would like to use just external txt file, but i don't know how to point it's location.

I decided to make it using Property file, i put it in src/res folder. It work correct while i'm trying it inside Intellij Idea, but when i build jar (artifact) i get java.io.FileNotFoundException

I tried two ways: This one was just copied private String getFile(String fileName) {

    StringBuilder result = new StringBuilder("");

    //Get file from resources folder
    ClassLoader classLoader = getClass().getClassLoader();
    File file = new File(classLoader.getResource(fileName).getFile());
    System.out.println(file.length());

    try (Scanner scanner = new Scanner(file)) {

        while (scanner.hasNextLine()) {
            String line = scanner.nextLine();
            result.append(line).append("\n");
        }

        scanner.close();

    } catch (IOException e) {
        e.printStackTrace();
    }

    return result.toString();

}
System.out.println(obj.getFile("res/cfg.txt"));</code>

And second one using Properties class:

try(FileReader reader =  new FileReader("src/res/cfg.txt")) {
Properties properties = new Properties();
properties.load(reader);
System.out.println(properties.get("password"));
}catch (Exception e) {
e.printStackTrace();
System.out.println(e);
}

In both ways i get java.io.FileNotFoundException. What is right way to attach config file like that?

Bukas
  • 35
  • 1
  • 8
  • 1
    `File f = new File(System.getProperty("user.home"), "my-settings.txt");` – Elliott Frisch Jan 12 '19 at 19:07
  • you have to ensure, the (property) file is included into the jar. (as I understand the problem: works in IntelliJ, doesn' work outside!?) ..and in intelliJ is `src/res` somehow linked to the (root of the) classpath. – xerx593 Jan 12 '19 at 19:08
  • @ElliottFrisch as i understood it creates new file in "C:\Users" folder and it will always be there, so i don't need to look for it because it's always there, right? – Bukas Jan 12 '19 at 19:17
  • @ElliottFrisch please, add this as an answer, i want to mark it as the most correct – Bukas Jan 12 '19 at 19:50

2 Answers2

3

Since the file is inside a .JAR, it can't be accessed via new File(), but you can still read it via the ClassLoader:

Properties properties = new Properties();
try (InputStream stream = getClass().getResourceAsStream("/res/cfg.txt")) {
    properties.load(stream);
}

Note that a JAR is read-only. So this approach won't work.

If you want to have editable configuration, you should place your cfg.txt outside the JAR and read it from the filesystem. For example like this:

Properties properties = new Properties();
File appPath = new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getParentFile();
try (InputStream stream = new FileInputStream(new File(appPath, "cfg.txt"))) {
    properties.load(stream);
}
rustyx
  • 80,671
  • 25
  • 200
  • 267
  • How exactly should i find the file? It can be placed and replaced in any directory – Bukas Jan 12 '19 at 19:56
  • The code I showed automatically determines the directory where the JAR file is located. So you can just keep the config file together with the JAR (not inside the JAR, just in the same folder where the JAR is) – rustyx Jan 12 '19 at 20:24
1

There are multiple places your can place your configuration options, and a robust deployment strategy will utilize some (or all) of the following techniques:

  • Storing configuration files in a well known location relative to the user's home folder as I mentioned in the comments. This works on Windows (C:\Users\efrisch), Linux (/home/efrisch) and Mac (/Users/efrisch)

    File f = new File(System.getProperty("user.home"), "my-settings.txt");
    
  • Reading environment variables to control it

    File f = new File(System.getenv("DEPLOY_DIR"), "my-settings.txt");
    
  • Using a decentralized service such as Apache ZooKeeper to store your database settings

  • Use Standalone JNDI (or the JNDI built-in to your deployment target)

  • Use a Connection Pool

Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249