What Is the Cross-Platform Way of Obtaining the Path to the Local Application Data Directory

What is the cross-platform way of obtaining the path to the local application data directory?

You could probably say something like (contradict me if I am wrong, or if this a bad approach)

private String workingDirectory;
//here, we assign the name of the OS, according to Java, to a variable...
private String OS = (System.getProperty("os.name")).toUpperCase();
//to determine what the workingDirectory is.
//if it is some version of Windows
if (OS.contains("WIN"))
{
//it is simply the location of the "AppData" folder
workingDirectory = System.getenv("AppData");
}
//Otherwise, we assume Linux or Mac
else
{
//in either case, we would start in the user's home directory
workingDirectory = System.getProperty("user.home");
//if we are on a Mac, we are not done, we look for "Application Support"
workingDirectory += "/Library/Application Support";
}
//we are now free to set the workingDirectory to the subdirectory that is our
//folder.

Note that, in this code, I am taking full advantage that Java treats '/' the same as '\\' when dealing with directories. Windows uses '\\' as pathSeparator, but it is happy with '/', too. (At least Windows 7 is.) It is also case-insensitive on it's environment variables; we could have just as easily said workingDirectory = System.getenv("APPDATA"); and it would have worked just as well.

Platform-independent way to get a path to store program data

The system property user.home should be pretty standard across most desktop systems.

System.out.println(System.getProperty("user.home"));

Note that this is the user the Java process runs under - so in case of server-side Java process, you would need to store information for the users of your app in your own data structure, as your app's users are not known to the OS.

Regarding a system-wide storage location, you may need to detect the OS version and compute the path. Another problem is that you would most likely need to escalate privileges to write to a system-wide location.

Where to store data between runs in Java

I guess it depends on your requirements. Something that should work on every(?) OS is using the application's own folder (or a sub folder of that):

String dir = System.getProperty("user.dir");

How can I get the path to the %APPDATA% directory in Python?

import os
print os.getenv('APPDATA')

How to get local application data folder in Java?

Reading the "Shell Folders" registry key is deprecated starting from Windows 95. The registry key contains a note saying "!Do not use this registry key. Use the SHGetFolderPath or SHGetKnownFolderPath instead." I had to find this out the hard way on a Vista system where all the keys were missing except for the warning note.

This related stackoverflow answer solves this problem on Windows using JNA, which is the solution I'm currently using.

Accessing platform-specific application data area

In Java, I need to find a way to store some data locally so that it is available between reboots. Simple things, such as window
location/size.

I think Preferences API suits this requirement. In a nutshell:

Applications require preference and configuration data to adapt to the
needs of different users and environments. The java.util.prefs package
provides a way for applications to store and retrieve user and system
preference and configuration data. The data is stored persistently in
an implementation-dependent backing store. There are two separate
trees of preference nodes, one for user preferences and one for system
preferences.

There is a short yet useful tutorial here. And here is a little example based on your requirements:

import java.util.prefs.Preferences;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class SwingPreferencesTest {

private void createAndShowGUI() {

JTextField dummyTextField = new JTextField(20);

JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(dummyTextField);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);

Preferences prefs = Preferences.userRoot().node(this.getClass().getName());

// Define default values here
System.out.println("width: " + prefs.getDouble("width", 100d));
System.out.println("height: " + prefs.getDouble("height", 100d));
System.out.println("x: " + prefs.getDouble("x", 0d));
System.out.println("y: " + prefs.getDouble("y", 0d));

// Set new values here
prefs.putDouble("width", frame.getPreferredSize().getWidth());
prefs.putDouble("height", frame.getPreferredSize().getHeight());
prefs.putDouble("x", frame.getLocationOnScreen().getX());
prefs.putDouble("y", frame.getLocationOnScreen().getY());
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new SwingPreferencesTest().createAndShowGUI();
}
});
}
}

If you run it the first time you'll see the preferences default values in console:

width: 100.0
height: 100.0
x: 0.0
y: 0.0

If you run it again then these values are updated. In my case:

width: 240.0
height: 59.0
x: 130.0
y: 130.0

Edit

As per @Puce comment below, on Windows data is stored in the registry and it makes sense because it's the way that Windows uses to store user/system/software data. You can find the registry entry generated in the example under HKEY_CURRENT_USER\JavaSoft\Prefs\[package\class name] as shown in picture below:

Sample Image

Note: tested on Windows 8 x64, JDK 1.7

If you don't want to fill the registry with these preferences, then you can just store a path to your application folder (as other applications do) and use this path to load config data from plain properties files. The main advantage to keep using Preferences (at least to store the application's path) is the mechanism to retrieve/store config data is designed to be cross-platform and JVM implementers (not developers) are who have to deal with the actual implementation.



Related Topics



Leave a reply



Submit