Platform-independent way for storing application data

Discussion in 'Java' started by Jan Thomä, Feb 18, 2009.

  1. Jan Thomä

    Jan Thomä Guest

    Hi,

    i am currently trying to find a way to store application data in a
    platform independent way. I have a derby database which i need to store
    somewhere on the user's PC. On Windows a place for this would be
    C:\Documents and Settings\<username>\Application Data. On Mac OS x the
    path would be /home/<username>/Library/Application Support/. However I
    don't want to hard code these locations as (especially when using
    multilanguage versions of windows) they might be different on any
    system. I know that i can store preferences with the preferences API
    that is part of the JDK, but this doesnt work for my Derby database
    file. Is there an API (maybe even inside the JDK) that allows me to
    retrieve the system dependent folder name where application data is to
    be stored? Any help would be greatly appreciated.

    Best regards,
    Jan
     
    Jan Thomä, Feb 18, 2009
    #1
    1. Advertising

  2. Jan Thomä

    Stefan Ram Guest

    Jan Thomä <> writes:
    >Is there an API (maybe even inside the JDK) that allows me to
    >retrieve the system dependent folder name where application
    >data is to be stored? Any help would be greatly appreciated.


    I did a search for existing specifications and implementations
    for this.

    After getting no results, I wrote a specification and
    implementation myself.

    Portadir intends to establich a vocabulary for directories:

    http://www.purl.org/stefan_ram/pub/the_portadir_specification

    Here is a preliminary publication of the class »FileSystem«
    that implements some directories specified in Portadir.

    http://www.purl.org/stefan_ram/java/FileSystem.java

    The regular publication is expected to be part of the next
    release of »ram.jar«.
     
    Stefan Ram, Feb 18, 2009
    #2
    1. Advertising

  3. Jan Thomä wrote on 19.02.2009 00:26:
    > Hi,
    >
    > i am currently trying to find a way to store application data in a
    > platform independent way. I have a derby database which i need to store
    > somewhere on the user's PC. On Windows a place for this would be
    > C:\Documents and Settings\<username>\Application Data. On Mac OS x the
    > path would be /home/<username>/Library/Application Support/. However I
    > don't want to hard code these locations as (especially when using
    > multilanguage versions of windows) they might be different on any
    > system. I know that i can store preferences with the preferences API
    > that is part of the JDK, but this doesnt work for my Derby database
    > file. Is there an API (maybe even inside the JDK) that allows me to
    > retrieve the system dependent folder name where application data is to
    > be stored? Any help would be greatly appreciated.


    What's wrong with System.getProperty("user.home")

    File datadir = new File(System.getProperty("user.home"), "MyAppData")
     
    Thomas Kellerer, Feb 19, 2009
    #3
  4. Jan Thomä

    Stefan Ram Guest

    Jan Thomä <> writes:
    >Is there an API (maybe even inside the JDK) that allows me to
    >retrieve the system dependent folder name where application
    >data is to be stored?


    In addition to my previous answer:

    The direct answer to your question is: »No« (as of JDK 1.6).

    (What you are looking for is called »user var directory« in
    Portadir.)

    I also tried to find this: Let's use Windows as an example.

    Windows has a set of system variables called »Shell Folders«,
    the Shell Folder you are looking for is called »AppData«.

    There is no way to read »AppData« by only using Java SE.

    Some parts of the Windows-JDK access the Shell Folders
    internally, for example to configure and install Java itself,
    but these features are not accessible to Java applications.

    Under Windows, an application can access these variables with
    JNI, but this would be a solution for this platform only.

    Another option would be to ask the user for the folder to be
    used upon the first time your programm is started and then
    remember his choice (think of the Eclipse »workspace«).

    Another option would be to accept the path to this folder via
    a command line argument, for example, »-Dapp.data=path«. Then
    it could be provided by a small shell script wrapping the
    application start.

    Remember: The Shell Folder AddData does not always have to be
    »C:\Documents and Settings\<username>\Application Data«,
    it can be somewhere else (for example under Windows 98)
    and it could have been relocated by the user or administrator
    to any other location. So you can not get it by obtaining
    the username and then using
    C:\Documents and Settings\<username>\Application Data
    . It needs to be obtained using the Win32-Shell-Folders-API.

    (Mozilla Firefox and K-Melon have the bad habit to actually
    /modify/ this Shell Variable back to the Windows default (at
    least at my site), which disturbs up a lot of other software.
    One has to manually restore it back to the path wanted.)
     
    Stefan Ram, Feb 19, 2009
    #4
  5. Jan Thomä

    Guest

    On Feb 18, 11:49 pm, -berlin.de (Stefan Ram) wrote:
    ....
    > http://www.purl.org/stefan_ram/java/FileSystem.java


    Is your whole post (and code example) sarcasm?

    Broken lazy instantiation, use of "Windows" backslash
    file separator in the .java source code (which is a big
    no-no), misuse of the "multiline comments", no proper
    Javadocs, etc.

    That .java source file is worthy of the daily WTF IMHO.

    Is this a way to help the original poster and is
    this way to help future readers, browsing the
    archives, looking for an answer to the same problem,
    by marking your post as "non archivable" ?
     
    , Feb 19, 2009
    #5
  6. In article
    <>,
    wrote:

    > On Feb 18, 11:49 pm, -berlin.de (Stefan Ram) wrote:
    > ...
    > > http://www.purl.org/stefan_ram/java/FileSystem.java

    >
    > Is your whole post (and code example) sarcasm?
    >
    > Broken lazy instantiation, use of "Windows" backslash
    > file separator in the .java source code (which is a big
    > no-no), misuse of the "multiline comments", no proper
    > Javadocs, etc.


    I am unable to locate a backslash used as a file separator, except in
    the helpful comments. The example is distributed under the terms of GNU
    Public License, should you wish amplify the documentation.

    > That .java source file is worthy of the daily WTF IMHO.


    I enjoy that site immensely, but you may wish to prepare yourself for
    rejection.

    > Is this a way to help the original poster and is
    > this way to help future readers, browsing the
    > archives, looking for an answer to the same problem,
    > by marking your post as "non archivable" ?


    I'm sorry, I seem to have overlooked your contribution.

    --
    John B. Matthews
    trashgod at gmail dot com
    <http://sites.google.com/site/drjohnbmatthews>
     
    John B. Matthews, Feb 19, 2009
    #6
  7. In article <>,
    Thomas Kellerer <> wrote:

    > Jan Thomä wrote on 19.02.2009 00:26:
    > > Hi,
    > >
    > > i am currently trying to find a way to store application data in a
    > > platform independent way. I have a derby database which i need to
    > > store somewhere on the user's PC. On Windows a place for this would
    > > be C:\Documents and Settings\<username>\Application Data. On Mac OS
    > > x the path would be /home/<username>/Library/Application Support/.
    > > However I don't want to hard code these locations as (especially
    > > when using multilanguage versions of windows) they might be
    > > different on any system. I know that i can store preferences with
    > > the preferences API that is part of the JDK, but this doesnt work
    > > for my Derby database file. Is there an API (maybe even inside the
    > > JDK) that allows me to retrieve the system dependent folder name
    > > where application data is to be stored? Any help would be greatly
    > > appreciated.

    >
    > What's wrong with System.getProperty("user.home")
    >
    > File datadir = new File(System.getProperty("user.home"), "MyAppData")


    In addition to this very useful suggestion, I have found Preferences a
    convenient, cross-platform repository for small amounts of data:

    <http://java.sun.com/javase/6/docs/api/java/util/prefs/Preferences.html>

    --
    John B. Matthews
    trashgod at gmail dot com
    <http://sites.google.com/site/drjohnbmatthews>
     
    John B. Matthews, Feb 19, 2009
    #7
  8. Jan Thomä

    Stefan Ram Guest

    Thomas Kellerer <> writes:
    >What's wrong with System.getProperty("user.home")


    In <-berlin.de> I wrote:

    | A footnote to anticipate answers involving »user.home«:
    |
    | The documentation says this:
    |
    | »This set of system properties always includes values for
    | the following key: [...]
    |
    | user.home User's home directory
    | user.dir User's current working directory«
    |
    |http://download.java.net/jdk7/docs/api/java/lang/System.html
    |
    | »java.lang.System.getProperty( "user.home" )« might sound
    | good, but gives »C:\WINDOWS« on Windows 9x, which might not be
    | the best place for user documents.
    |
    | It is not only broken on Windows 9x, but also on Windows NT:
    |
    | »We made a conscious decision to change the definition of
    | the "user.home" property on Win32; see 4100238 for more
    | info. This is not a bug.«
    |
    |http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4162112
    |
    | (If Sun Microsystems, Inc. is free to make such a decision,
    | but why don't they document it at the appropriate place, that is, in
    | http://download.java.net/jdk7/docs/api/java/lang/System.html?)
    |
    | It also is broken on Vista:
    |
    |http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6519127
    |
    | And also Microsoft®'s VM does it wrong:
    |
    |http://support.microsoft.com/kb/221206
    |
    | So we know now that there is a conspiracy among JVM producers
    | to make »java.lang.System.getProperty( "user.home" )« unusable.
    | (When it can not be used on Windows, it can not be used in a
    | portable desktop Java program generally, because this should run
    | under /all/ supported platforms.)
    |
     
    Stefan Ram, Feb 19, 2009
    #8
  9. Jan Thomä

    Stefan Ram Guest

    -berlin.de (Stefan Ram) writes:
    >|http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4162112
    >|http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6519127
    >|http://support.microsoft.com/kb/221206


    Another report:

    »On every other platform, the "user.home" system property
    is a sensible, sane location in which to store documents.
    Under Windows, it is not.«

    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5045575

    The OP was not actually searching for a user home directory,
    but for a directory to store application data. In this case it
    might not be this disturbing that user.home often is not the
    user home directory. But the irregular mapping of user.home to
    directories with different semantics under different
    platforms, different versions of Windows and different
    versions of Java can still be disturbing.
     
    Stefan Ram, Feb 19, 2009
    #9
  10. On 2009-02-18 18:49:46 -0500, -berlin.de (Stefan Ram) said:

    > Jan Thomä <> writes:
    >> Is there an API (maybe even inside the JDK) that allows me to
    >> retrieve the system dependent folder name where application
    >> data is to be stored? Any help would be greatly appreciated.

    >
    > I did a search for existing specifications and implementations
    > for this.
    >
    > After getting no results, I wrote a specification and
    > implementation myself.
    >
    > Portadir intends to establich a vocabulary for directories:
    >
    > http://www.purl.org/stefan_ram/pub/the_portadir_specification
    >
    > Here is a preliminary publication of the class »FileSystem«
    > that implements some directories specified in Portadir.
    >
    > http://www.purl.org/stefan_ram/java/FileSystem.java
    >
    > The regular publication is expected to be part of the next
    > release of »ram.jar«.
    >


    I had a quick gander at the Portadir source and, while it's good, I
    think it's missing some crucial bits. Allow me to elaborate on the
    pointless incompatabilities between OSes for a moment.

    Under linux, and indeed most unices, the conventions for storing user data are:
    1. Preferences in $HOME/.appname or $HOME/.appname/some/subpath.
    2. Other data either in the cwd or in $HOME/something.
    There are no APIs for locating these places, because the conventions
    are so simple you don't actually need one.

    Under Mac OS, which is technically a Unix but doesn't act like one,
    things are a little more complicated:
    1. Preferences stored in the preferences system, which is ultimately
    backed by .plist files (specifically) in specific locations, searched
    in a particular order. There is an API for setting and getting the
    preferences for a given "domain" (read "application"). User-specific
    preferences go in
    ~/Library/Preferences/com.example.your.domain.here.plist, should you
    need to manipulate them directly. In Apple's JVM, the default
    java.util.Preferences provider is aware of this system.
    2. "Documents" - that is, freestanding files users directly care about
    and manipulate, under $HOME/Documents[0], with the exact subdirectory
    and name up to the user via the save dialog.
    3. "Application Data" - that is, files the app needs to maintain in
    order to run but that aren't intended for normal manipulation by users
    - go in an "Application Data" folder, which is ~/Library/Application
    Data/, organized by application name (usually).
    There's an added complication in that all of thse names are
    localizable; however, there are also APIs for looking up the physical
    paths for the various special locations. These APIs are part of the OS
    X API, not POSIX or any other standard.

    Under Windows, things are pretty much as they are under Mac OS, except
    that preferences go in the registry, instead of on the filesystem. Once
    again, the default java.util.Preferences provider is aware of this and
    does the right thing. There are APIs for looking up the documents and
    per-user application data directories, which are part of the Windows
    API and are relatively incompatible with their Mac equivalents.

    The practical upshot is that the only things you can rely on are:

    - The user's home director is at ${user.home} but may not be the right
    "default" save location.
    - The Preferences API knows where to store settings in a
    platform-dependent way.
    - The current directory is at ${user.dir} but may not be the right
    "default" save location either, for GUI apps. It's reliable for
    command-line apps.
    - The default Swing L&F probably gets the save dialog right if you
    don't specify a directory yourself.

    Unfortunately, there's no straightforward way to get either the
    Application Data directory or the actual default save location for the
    platform. While I'd love to see those in Portadir, I don't imagine it
    happening. Writing a portable Java GUI app and getting all of the
    various directories correct is pretty much impossible.

    I apologize for the disjointed nature of this post; I'm TIRED and I've
    been answering phones all day.

    -o

    [0] Actually, it's worse than that. There are ~/Documents, ~/Music,
    ~/Movies, ~/Pictures, and ~/Downloads, and application authors are
    expected to use the correct one. All of these names are localised, to
    boot.
     
    Owen Jacobson, Feb 19, 2009
    #10
  11. On 2009-02-19 00:02:58 -0500, -berlin.de (Stefan Ram) said:

    > -berlin.de (Stefan Ram) writes:
    >> |http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4162112
    >> |http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6519127
    >> |http://support.microsoft.com/kb/221206

    >
    > Another report:
    >
    > »On every other platform, the "user.home" system property
    > is a sensible, sane location in which to store documents.
    > Under Windows, it is not.«
    >
    > http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5045575
    >
    > The OP was not actually searching for a user home directory,
    > but for a directory to store application data. In this case it
    > might not be this disturbing that user.home often is not the
    > user home directory. But the irregular mapping of user.home to
    > directories with different semantics under different
    > platforms, different versions of Windows and different
    > versions of Java can still be disturbing.


    On OS X, user.home is not a sensible place for storing application
    data. It's close, and it's probably acceptable for documents, but for
    application internal data (for example, a newsreader's downloaded
    article cache), both user.home and ${user.home}/.app/something are
    irritatingly wrong.

    -o
     
    Owen Jacobson, Feb 19, 2009
    #11
  12. Jan Thomä

    Jan Thomä Guest

    Hi again,

    thanks for all your answers and the discussion. It seems there is no
    easy way of doing this. A friend of mine pointed me to JS-296, which
    has a class LocalStorage which provides exactly the directory I had in
    mind. Their code is:

    public File getDirectory() {
    if (directory == unspecifiedFile) {
    directory = null;
    String userHome = null;
    try {
    userHome = System.getProperty("user.home");
    }
    catch(SecurityException ignore) {
    }
    if (userHome != null) {
    String applicationId = getApplicationId();
    OSId osId = getOSId();
    if (osId == OSId.WINDOWS) {
    File appDataDir = null;
    try {
    String appDataEV = System.getenv("APPDATA");
    if ((appDataEV != null) && (appDataEV.length() > 0)) {
    appDataDir = new File(appDataEV);
    }
    }
    catch(SecurityException ignore) {
    }
    String vendorId = getVendorId();
    if ((appDataDir != null) && appDataDir.isDirectory()) {
    // ${APPDATA}\{vendorId}\${applicationId}
    String path = vendorId + "\\" + applicationId + "\\";
    directory = new File(appDataDir, path);
    }
    else {
    // ${userHome}\Application Data\${vendorId}\${applicationId}
    String path = "Application Data\\" + vendorId + "\\" + applicationId + "\\";
    directory = new File(userHome, path);
    }
    }
    else if (osId == OSId.OSX) {
    // ${userHome}/Library/Application Support/${applicationId}
    String path = "Library/Application Support/"+applicationId+"/";
    directory = new File(userHome, path);
    }
    else {
    // ${userHome}/.${applicationId}/
    String path = "."+applicationId+"/";
    directory = new File(userHome, path);
    }
    }
    }
    return directory;
    }

    So on Windows, they are using a system environment variable to find out
    the localized name of the application data folder. I am not quite sure
    if their Mac OS X implementation is correct, as Owen Jacobson pointed
    out that Mac OS X directories are localized as well. I cannot confirm
    this right now, they don't seem to be localized on my machine, at least
    not on the console level. It looks like finder is doing some fancy
    things creating localized names for the folders. But when you look on
    console level, all folders are in "plain english", so their code might
    actually work.

    Best regards,
    Jan
     
    Jan Thomä, Feb 19, 2009
    #12
  13. Jan Thomä

    Stefan Ram Guest

    Jan Thomä <> writes:
    >String appDataEV = System.getenv("APPDATA");


    This will work under Windows 2000/XP/Vista, but not under
    Windows 95/98. I have no report about Windows ME, but assume
    that it behaves like 95/98 in this regard. I do not have any
    idead about Windows NT in this regard.

    The Win32-call »GetFolderPath( CSIDL_APPDATA )« (from C or
    C++) should work on Windows 98 (possibly, 95) and all later
    versions of Windows. (But, of course, is not possible in pure
    Java, only in C. Also, it uses shell32.dll and user32.dll,
    which are reported to consume a lot of precious »desktop
    heap«, a lack of which could lead to application failures.)
     
    Stefan Ram, Feb 19, 2009
    #13
  14. Jan Thomä

    Stefan Ram Guest

    Owen Jacobson <> writes:
    >On OS X, user.home is not a sensible place for storing application
    >data. It's close, and it's probably acceptable for documents, but for
    >application internal data (for example, a newsreader's downloaded
    >article cache), both user.home and ${user.home}/.app/something are
    >irritatingly wrong.


    ${user.home}/.app is wrong. But if you feel commited to pure Java,
    and can only get 3 or 4 different paths from the environment, it
    might still be the choice least worse among those paths.

    You can preconfigure this as a default for uneduated users, and
    educated users then might change this to a better place during
    the installation of the application.
     
    Stefan Ram, Feb 19, 2009
    #14
  15. In article <-berlin.de>,
    -berlin.de (Stefan Ram) wrote:

    > Owen Jacobson <> writes:
    > >On OS X, user.home is not a sensible place for storing application
    > >data. It's close, and it's probably acceptable for documents, but for
    > >application internal data (for example, a newsreader's downloaded
    > >article cache), both user.home and ${user.home}/.app/something are
    > >irritatingly wrong.

    >
    > ${user.home}/.app is wrong. But if you feel commited to pure Java,
    > and can only get 3 or 4 different paths from the environment, it
    > might still be the choice least worse among those paths.


    Eclipse, Netbeans and a handful of Java applications I use do this.

    > You can preconfigure this as a default for uneduated users, and
    > educated users then might change this to a better place during
    > the installation of the application.


    Out of curiosity, what's the downside?

    --
    John B. Matthews
    trashgod at gmail dot com
    <http://sites.google.com/site/drjohnbmatthews>
     
    John B. Matthews, Feb 19, 2009
    #15
  16. Jan Thomä

    Jan Thomä Guest

    On 2009-02-19 14:33:18 +0100, -berlin.de (Stefan Ram) said:

    > Jan Thomä <> writes:
    >> String appDataEV = System.getenv("APPDATA");

    >
    > This will work under Windows 2000/XP/Vista, but not under
    > Windows 95/98. I have no report about Windows ME, but assume
    > that it behaves like 95/98 in this regard. I do not have any
    > idead about Windows NT in this regard.



    Well since Windows 95/98/NT have reached EOL already, i don't really
    see this as a problem. Java 1.5 does not support Windows 95/NT either,
    so this is not an issue in that regard. I'd deem the approach with
    APPDATA as good enough for the vast majority of systems out there (and
    for my purposes). At least it is definitely not worth going with JNI
    for these systems...

    Jan
     
    Jan Thomä, Feb 19, 2009
    #16
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. MK
    Replies:
    1
    Views:
    842
    Peter Hansen
    Jun 25, 2003
  2. Gandalf
    Replies:
    1
    Views:
    307
    Lawrence Oluyede
    Aug 18, 2004
  3. =?iso-8859-1?B?QW5kcuk=?=
    Replies:
    8
    Views:
    386
    =?iso-8859-1?B?QW5kcuk=?=
    May 1, 2007
  4. Stef Mientki
    Replies:
    31
    Views:
    736
    Paul McNett
    Oct 24, 2008
  5. Daniel Fetchinson
    Replies:
    49
    Views:
    1,364
    alex23
    Aug 6, 2010
Loading...

Share This Page