Find place for dedicated application folder

I'm sorry if this title is badly named, I can't think of a better way to phrase it and so edits would be welcomed.

Most applications I've seen that require hard drive file storage create a folder in a suitable place depending on the operating system. On Windows these folders lie in \Users\[current user]\AppData\[etc], on Mac these folders lie in /Users/[current user]/Library/Application Support/[etc], Ubuntu has a similar thing that I can't think of right now.

I would like to know, how are these file paths consistently found in differing operating systems with different users, and is there, at least in java, a simple way to achieve this?

Thank you.


There should be, but there isn't. I even submitted a bug/RFE about it, but as far as I know, it was never accepted. Here's what I use:

public class ApplicationDirectories {
    private static final Logger logger =
        Logger.getLogger(ApplicationDirectories.class.getName());

    private static final Path config;

    private static final Path data;

    private static final Path cache;

    static {
        String os = System.getProperty("os.name");
        String home = System.getProperty("user.home");

        if (os.contains("Mac")) {
            config = Paths.get(home, "Library", "Application Support");
            data = config;
            cache = config;
        } else if (os.contains("Windows")) {
            String version = System.getProperty("os.version");
            if (version.startsWith("5.")) {
                config = getFromEnv("APPDATA", false,
                    Paths.get(home, "Application Data"));
                data = config;
                cache = Paths.get(home, "Local Settings", "Application Data");
            } else {
                config = getFromEnv("APPDATA", false,
                    Paths.get(home, "AppData", "Roaming"));
                data = config;
                cache = getFromEnv("LOCALAPPDATA", false,
                    Paths.get(home, "AppData", "Local"));
            }
        } else {
            config = getFromEnv("XDG_CONFIG_HOME", true,
                Paths.get(home, ".config"));
            data = getFromEnv("XDG_DATA_HOME", true,
                Paths.get(home, ".local", "share"));
            cache = getFromEnv("XDG_CACHE_HOME", true,
                Paths.get(home, ".cache"));
        }
    }

    /** Prevents instantiation. */
    private ApplicationDirectories() {
    }

    /**
     * Retrieves a path from an environment variable, substituting a default
     * if the value is absent or invalid.
     *
     * @param envVar name of environment variable to read
     * @param mustBeAbsolute whether enviroment variable's value should be
     *                       considered invalid if it's not an absolute path
     * @param defaultPath default to use if environment variable is absent
     *                    or invalid
     *
     * @return environment variable's value as a {@code Path},
     *         or {@code defaultPath}
     */
    private static Path getFromEnv(String envVar,
                                   boolean mustBeAbsolute,
                                   Path defaultPath) {
        Path dir;
        String envDir = System.getenv(envVar);
        if (envDir == null || envDir.isEmpty()) {
            dir = defaultPath;
            logger.log(Level.CONFIG,
                envVar + " not defined in environment"
                + ", falling back on \"{0}\"", dir);
        } else {
            dir = Paths.get(envDir);
            if (mustBeAbsolute && !dir.isAbsolute()) {
                dir = defaultPath;
                logger.log(Level.CONFIG,
                    envVar + " is not an absolute path"
                    + ", falling back on \"{0}\"", dir);
            }
        }
        return dir;
    }

    /**
     * Returns directory where the native system expects an application
     * to store configuration files for the current user.  No attempt is made
     * to create the directory, and no checks are done to see if it exists.
     *
     * @param appName name of application
     */
    public static Path configDir(String appName)
    {
        return config.resolve(appName);
    }

    /**
     * Returns directory where the native system expects an application
     * to store implicit data files for the current user.  No attempt is made
     * to create the directory, and no checks are done to see if it exists.
     *
     * @param appName name of application
     */
    public static Path dataDir(String appName)
    {
        return data.resolve(appName);
    }

    /**
     * Returns directory where the native system expects an application
     * to store cached data for the current user.  No attempt is made
     * to create the directory, and no checks are done to see if it exists.
     *
     * @param appName name of application
     */
    public static Path cacheDir(String appName)
    {
        return cache.resolve(appName);
    }
}

Some notes:

I'm not sure the code for older Windows versions is even necessary, as Java 8 doesn't run on Windows XP.

The XDG Directory Specification says “All paths set in these environment variables must be absolute. If an implementation encounters a relative path in any of these variables it should consider the path invalid and ignore it.”


The directory can be found with the method

static String defaultDirectory() {
    String os = System.getProperty("os.name").toLowerCase();
    if (OS.contains("win"))
        return System.getenv("APPDATA");
    else if (OS.contains("mac"))
        return System.getProperty("user.home") + "/Library/Application Support";
    else if (OS.contains("nux"))
        return System.getProperty("user.home");
    else
        return System.getProperty("user.dir");
}

It is worth noting that on Linux any such folders should be hidden by beginning their name with .

(Answer found from users CodeBunny and Denis Tulskiy on this post)