57

What I need is a platform-independent way of obtaining the path to the local application data directory. System.getenv("LOCALAPPDATA") seems to work only with Windows. How do I go about this?

missingfaktor
  • 88,931
  • 61
  • 278
  • 362

6 Answers6

44

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.

spongebob
  • 8,552
  • 13
  • 45
  • 80
Mike Warren
  • 3,413
  • 4
  • 36
  • 87
  • An important sidenote: saying `private final String workingDirectory = System.getenv("AppData") + File.separatorChar + ourFolder;` and then `private File dataFolder = new File("workingDirectory");` `System.out.println("Our dataFolder was " + ((dataFolder.mkdir()) ? "" : "not ") + "created successfully");` does NOT guarantee that the parent directory of `dataFolder` will be the `AppData` folder. //In my case, this was stored in `Roaming`. – Mike Warren May 21 '13 at 21:19
  • Also, you might want to get yourself access to a Linux OS and test this code; Ubuntu is Linux, and I have no idea if `"user.home"` is a valid property on that OS; my experience with Linux doesn't include playing around on there. `//Happy coding, and you might want to accept an answer.` – Mike Warren Jul 05 '13 at 03:52
  • In addition, you might get a `SecurityException` on some machines: http://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html – Mike Warren Jul 05 '13 at 04:00
  • 2
    Apple advises not to hardcode the `Application Support` folder. E.g. your code would fail for sandboxed applications. – z80crew Oct 19 '13 at 14:48
  • Then, I shall directly name other folder that is subfolder of `System.getProperty("user.home");` that would probably be the folder to be directly used by the app, right? – Mike Warren Nov 10 '13 at 04:22
  • 1
    @MikeWarren I have tested that `"user.home"` property return `/home/username` as Windows does. And as a tip, use a directory that start with a dot if you wanna hide it as `user.home` is the user folder and normally program folder are hide (start with a dot). – PhoneixS Feb 12 '14 at 16:59
  • 1
    @MikeWarren Nice approach! Why not simply say `workingDirectory = System.getenv("AppData")` and then test if it's null to change it to UNIX location? – SteeveDroz Apr 16 '16 at 05:03
  • Didn't think of that at the time. Man, my answer got popular! – Mike Warren Apr 19 '16 at 15:33
  • 1
    got popular, but this answer has not been accepted yet? @MikeWarren – gumuruh Jun 29 '16 at 04:37
  • @z80crew can you cite a source for that? Doesn't give me an idea where to put data for sandboxed applications. – Andy Jun 04 '17 at 18:38
  • @Andy From the [App Sandbox Design Guide](https://developer.apple.com/library/content/documentation/Security/Conceptual/AppSandboxDesignGuide/MigratingALegacyApp/MigratingAnAppToASandbox.html): `For example, whereas a non-sandboxed app might store files in ~/Library/Application Support/, the sandboxed version of the same app does not have access to that directory`. – z80crew Jun 05 '17 at 10:34
  • @z80crew wait a minute, can Java even run inside the OSX App Sandbox? (not to be confused with Java's own security sandboxing) – Andy Jun 05 '17 at 22:23
  • @Andy I don't know. Left Java behind since a very long time now. – z80crew Jun 06 '17 at 09:24
  • @z80crew understandable! – Andy Jun 07 '17 at 00:21
  • IMO this answer is wrong in several ways. In addition to the Mac sandbox violation, it hardcodes the Mac path even on Linux, and on Windows it uses environment variables (which might be not present at all, or messed with by the user), instead of calling the documented OS APIs on each OS to get to special folders. This can and will fail in unusual but valid cases. – marczellm Mar 06 '21 at 21:12
25

Personally, I found appdirs to be very helpful for similar use-cases. It has functions that locate different kinds of useful directories:

  • getUserDataDir
  • getUserConfigDir
  • getUserCacheDir
  • getUserLogDir
  • getSiteDataDir ← looks like this is the one you need
  • getSiteConfigDir

The locations it returns are more or less standard:

kirelagin
  • 12,718
  • 2
  • 42
  • 56
15

The questing is old but I am missing an answer listing environment vars instead of some funny absolute paths. I do not know anything about OSX. this post only contains information about windows and linux.

I have not enough points to extend an already existing answer so I have to write a new one.

Linux: As previously mentioned there exists something like freedesktop.org which is defining a standard the linux distributions are trying to fulfill. There is also a subpage defining environment variables and their default values (If they are not set they are empty by default. The application has to match the variable to the default). Link to that page: freedesktop.org env vars

Vars defined relevant for this question:

  • $XDG_DATA_HOME (local) (defaults to: $HOME/.local/share)
  • $XDG_CONFIG_HOME (local) (defaults to: $HOME/.config)
  • $XDG_DATA_DIRS (global) (defaults to: /usr/local/share/ or /usr/share/)
  • $XDG_CONFIG_DIRS (global) (defaults to: /etc/xdg)

Windows XP:

  • %APPDATA% (defaults to: C:\Documents and Settings{username}\Application Data)

  • %CommonProgramFiles% (defaults to: C:\Program Files\Common Files) (shared program files)

  • %CommonProgramFiles(x86)% (defaults to: C:\Program Files (x86)\Common Files) (64-bit only!) (shared program files)

  • %ProgramFiles% (defaults to: %SystemDrive%\Program Files)

  • %ProgramFiles(x86)% (defaults to: %SystemDrive%\Program Files (x86) (only in 64-bit version)) (64-bit only!)

Windows Vista +:

  • %APPDATA% (defaults to: C:\Users{username}\AppData\Roaming) (Shared between linked workstations. User local. Save files and configs)
  • %LOCALAPPDATA% (defaults to: C:\Users{username}\AppData\Local) (User local. Save files and configs)
  • %CommonProgramFiles% (defaults to: C:\Program Files\Common Files) (shared program files)
  • %CommonProgramFiles(x86)% (defaults to: C:\Program Files (x86)\Common Files) (64-bit only!) (shared program files)

  • %ProgramFiles% (defaults to: %SystemDrive%\Program Files) (Static data that will not change after installation)

  • %ProgramFiles(x86)% (defaults to: %SystemDrive%\Program Files (x86) (only in 64-bit version)) (64-bit only!) (Static data that will not change after installation)

  • %ProgramData% (defaults to: %SystemDrive%\ProgramData) (Changeable data affecting all users)

In short: Linux has two environment variables which might not be set (one for configs, one for files). Windows has as far as I can tell only one environment var for configs and files together. Please use these instead of absolute paths.

IndianerJones
  • 865
  • 1
  • 8
  • 20
Fjolnir Dvorak
  • 304
  • 2
  • 13
  • 1
    Mac OS X locations are examined [here](http://apple.stackexchange.com/q/28928/20589). – trashgod Jan 23 '17 at 23:32
  • Windows XP doesn't have the **%LOCALAPPDATA%** variable, but it has the folder, it's at **%USERPROFILE%\Local Settings\Application Data** – user May 18 '19 at 12:22
9

For moderate amounts of data, consider java.util.prefs.Preferences, mentioned here, or javax.jnlp.PersistenceService, discussed here. Both are cross-platform.

Community
  • 1
  • 1
trashgod
  • 200,320
  • 28
  • 229
  • 974
  • @thrashgod could you provide an example of how to retrieve the local app data directory from `java.util.Preferences`? – Hummeling Engineering BV Jun 17 '15 at 08:36
  • 1
    Storing data directly in `Preferences` precludes the need to specify a [`workingDirectory`](http://stackoverflow.com/a/16660314/230513), as `Preferences` already abstracts the location. – trashgod Jun 17 '15 at 10:15
1

There is no cross platform way for that, because the concepts that the different OS-s use are too different to "abstract away". I am not familiar with *nix and Mac conventions, but on Windows there is no "home folder" and the application has to specify whether it wants to store stuff in the roaming profile (C:\Users\<username>\AppData\Roaming\<application vendor>\<application name>\ by default) or the local profile (C:\Users\<username>\AppData\Local\<application vendor>\<application name>\ by default).

Note that you cannot hardcode these paths, because on a networked installation they might be somewhere else. You shouldn't rely on environment variables either because they can be modified by the user. Your application should call the SHGetKnownFolderPath function of the Windows API.

The difference between the two is that the local profile is specific to the user and the machine, while the roaming profile is specific to the user, so in a setup like my university, stuff apps put in the roaming profile are uploaded to the server and synced to whichever computer I log in to.

It should be the responsibility of applications to choose whether the settings they want to store are local or roaming. Unfortunately Java does not allow apps to decide this. Instead there is a global user-configurable setting that determines which folder you'll get.

marczellm
  • 1,206
  • 1
  • 17
  • 39
-4

You can use this

String currentDir = new File(".").getAbsolutePath();

or this:

System.getProperty("user.dir")

I prefer the first option

Regards

esmoreno
  • 658
  • 5
  • 12
  • 1
    I believe you meant "user.home". "user.dir" is the current working directory, which is not guaranteed to be where the AppData folder is located – shieldgenerator7 Jan 28 '16 at 22:23