简体   繁体   中英

Simple Java Desktop App: Config files and where to put them

This feels like an absolute newbie question, but I'm on a colossal yak-shave over what should be an elementary concern.

I'm writing a simple desktop app in Java. (Scala actually, but let that pass.) It targets Windows machines. I want to package it and have it runnable without creating an installer, or messing about with the Windows registry. And I want a config file that users can find and edit in order to customize settings. (In the manner of SublimeText's user preferences, for example.)

I envision the following structure:

my-application/
|- bin/
   |- myApp.class (or myApp.jar, if you prefer)
|- files/
   |- config/
      |- config.json
   |- output/
      |- output.xlsx
|-runMyApp.bat

Inside Eclipse, relative paths tend to resolve to the myApplication/ directory, but if I run the app from the command-line, they resolve to whatever the -cp argument was. (Generally, the bin/ directory.)

Am I being naïve? Have I got the wrong paradigm entirely?

It seems to me it would be a fundamental thing to be able to consistently locate files (resources) in the file system surrounding your executables.

Please help!

To package an application means putting the classes in a .jar file, which is a zip file with one or more special Java-specific entries in it. (There are many Stack Overflow answers describing how to do this, such as Java: export to an .jar file in eclipse . Feel free to search for more.)

The problem is, an application cannot write to its own .jar file. On Windows the file is likely to be locked and unwritable; on other systems, it may be possible but is a bad idea for many reasons. You should always consider a .jar file read-only.

Since the configuration needs to be writable, it cannot live in your .jar file, but your .jar file can (and should) include your config.json as a default configuration. The actual configuration should be a file somewhere under the user's home directory; if it doesn't exist, your program should copy your default configuration to that location to allow future modification. Alternatively, your program could just ignore missing configuration and default to reading your internally packaged default configuration, but in that case, you'd want to provide thorough documentation of the writable configuration file's format for end users, since they won't have an example to go by.

Files packaged inside a .jar file are called resources and are read using the Class.getResource or Class.getResourceAsStream method. You cannot read them using File or Path objects, because they are parts of a zip archive, not actual files. Copying it to a writable location typically looks like this:

Path userConfigFile = /* ... */;

try (InputStream defaultConfig = getClass().getResourceAsStream("/config/config.json")) {
    Files.copy(defaultConfig, userConfigFile);
}

For more information on reading resources, you may want to read about Access to Resources .

On Windows, the actual location of a configuration file is usually in a subdirectory of the user's AppData directory:

Path configParent;

String appData = System.getEnv("APPDATA");
if (appData != null) {
    configParent = Paths.get(appData);
} else {
    configParent = Paths.get(
        System.getProperty("user.home"), "AppData", "Local");
}

Path configDir = configParent.resolve(applicationName);
Files.createDirectories(configDir);

Path userConfigFile = configDir.resolve("config.json");

If you're interested in discussion of where to place user configuration files on other platforms, see this question and this one .

The class File resolves relative paths by default in the user's current working directory (available as system property user.dir ). So, if you do cd on command line to change to a directory and then invoke the Java application this directory will be the current user's working directory from the point of view of the Java application.

One thing you can do is to pass your base-directory as system property to the Java application. This can be done within a shell script that starts your application by using it's own location.

Another possibility is to include the files like configuration file in classpath when invoking the Java application and to load them from classpath in Java application. The disadvantage of this solution is that the user can do more things than needed with damage as a possible result.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM