Ok, the question is quite simple.
I have a Java program, which I am extracting some save-files to an external location.
Right now, I use C:/ApplicationName, however, that is a very bad way to do that.
I know alot of locations i could use, for instance:
%Appdata%
C:\Program Files (x86)
C:\Users\Users\Documents (Ive seen some indie games use this.)
Other locations?
But I can't figure out, when to use the proper one.
And if i want to support Linux and OSX, is there a libary, which supports that, or do i manually have to wrap them into an if/else with System.getProperties("os.name")?
Keep in mind that sometimes when games save to a specific directory, they aren't built to be cross-platform.
There are two ways you could do this. The first (and personally my preferred version) is to save in the directory of the application. This also has the advantage of being portable. However, the saves are linked to the application, so if the user deletes the application and reinstalls later they'll lose their data (which may or may not be a good thing).
Another option is to use System.getProperty().
Specifically, you can use:
System.getProperty("user.dir");
System.getProperty("user.home");
System.getProperty("user.name");
To figure out where to put your files.
This will be a lot more complicated, so the first method is preferred.
If it's data the user does not need direct access to, such as stored application/game state data, then it's appropriate to store it in the user's application data directory. Try this:
1) Determine the OS.
2) Get the user home directory.
System.getProperty("user.home");
3) Append OS-specific application directory:
Mac: /Library/Application Support/MyApp
Windows: \\Application Data\\MyApp
Linux: MyApp (there's no convention here that I know of)
If the data needs to be exported, such as saving a document from your application, then ask the user where to store the file via a file dialog, defaulting to their Documents directory.
Related
Disclaimer:I know that this is something that is covered very early in learning Java, however, I am just a hobbyist and I am self-taught. I am only as good as the information I find online is. Please do not be derisive or condescending. We were all new at one time.
As mentioned, I have a written a Java Form app. What it does it takes user input and writes it to an Excel file. How can I dynamically reference a file (the Excel, in particular) that is on each users' computer, found in a different directory but not have to hardcode each user's exact file path and distribute individually?
Thanks!
I think you are looking for user.home property.
System.getProperty("user.home");
Which will give you, say, c:\users\mk
and then you can append your path to that.
You could have the application ask the user for the path.
As part of the application configuration have the user define an environment variable using a known name with either the desired directory or the install directory (then use the variable to derive the desired directory).
for example:
tell the user to define BLAMMY_HOME which contains the install location of your software (named BLAMMY).
derive the desired directory by concatinating the value of BLAMMY_HOME and "/desired/directory/name".
or
have the user define BLAMMY_SPOT which contains the full path the the desired directory.
use the value of BLAMMY_SPOT in your application.
Defaulting to using user.home is fine, but I (personally) do not like that technique (as a user).
Take an example of 2 users
UserA path: /opt/file/directories/target (contains the excel file)
UserB path: /opt/directories/target (contains the excel file)
There's absolutely no way to find the target directory (except searching for it, but then you might find another one) unless the application has access to some out of band information. For example, Java offers the user.home property
String pathPrefix = System.getProperty("user.home");
so you can use that and make your target directory relative to that.
That's the whole purpose of applications having installation/working directories. As another example, take the Windows Registry. Imagine you had to download a patch from the internet. The patch itself wouldn't be able to check all the paths on the file system until it found yours (each user has a different one). Instead, it can find that path from the Windows Registry (or something comparable depending on the application).
When we want to load a static file e.g. a picture, a sound file, a file containing information about a game map,... we can store them as resources in jar file and use getClass.getResource("images/splash.png") (also getResourceAsStream) to load and use them. But when we want to read and write into a file like settings file, I don't think using resources is a good way, because i think resources are designed to store read/only files that are not supposed to change, like splash screen image or a game's background music; These are my reasons to think this way:
That is why return value of getResourceAsStream is an instance of InputStream and we don't have a similar function which gives us an OutputStream, because we're not supposed to alter resource files.
Writing into resources changes program .jar file and i guess it's not a good thing at all; Because if we do so: we can't use check-sums to verify file, if we are a limited user and system administrator doesn't give us write permission we can't make changes into main .jar file, user-specific preferences are hard or impossible to implement,...
So, my questions are:
Which parts of my thoughts and assumptions are right or wrong?
If they're right what is the best(I mean short and portable between OSs and Computers) way to store files like that? (Application setting/preferences, A game save file, ...)
(#Some user who may wants to mark this as duplicate: I don't think my question is a duplicate, i searched in the site, I admit it has some common parts with some questions but it's not duplicate!)
Your three observations in #2 above are valid reasons not to store settings in a resource file, regardless of the APIs provided.
There are a variety of ways to save settings in Java, including:
The Java system property "user.home" provides the user's home directory, to which the user should have write access. You can create an application-specific subdirectory underneath it.
Java provides a Preferences API. This may store settings in a directory or (on Windows) in the registry.
OSGI provides a preferences API.
If you're using the Eclipse RCP, you can write to the configuration directory using a ConfigurationScope. See the Eclipse FAQ "What is a preference scope").
I am attempting to store the change made to my application's properties. The .properties file is located in resources package, which is different from the package that contains my UI and model.
I opened the package using:
this.getClass().getClassLoader().getResourceAsStream("resources/settings.properties")
Is there a functional equivalent of this that permits me to persist changes to the Properties Class in the same .Properties file?
In general, you cannot put stuff back into a resource you got from the classloader:
Class loader resources are often read-only; i.e. held in read-only files / read-only directories.
If you got the resource from a JAR file, JAR files are not simply updateable. (To "update" you need to extract the old JAR's contents and create a new JAR with the updated contents. It is all to do with the structure of ZIP files ...)
In some cases, the class loader resource will have been downloaded on-the-fly, and there is no way to push changes back to the place where you downloaded from.
Even if you can update a resource you got from the classloader, it is a bad idea / bad practice.
Doing this "pollutes" the clean application installation with a user's preferences. Among other things, this means that the installation cannot be shared with other users (unless you handle preferences for multiple users ...).
There are security issues with having applications installed as writeable so that embedded preferences can be updated. Think viruses! Think one user who might be inclined to trash another user's preferences!
There are administration issues with having user-specific copies of applications. And if the user has to install his own copy of an app, there are potential security issues with that as well.
There may be technical issues with file locking or caching on some platforms that either get in the way of (safe) updates or make it difficult for an application to load the updated resource without a restart.
Finally, this is NOT the way that system administrators (and educated users) expect software to behave. Java applications should deal with user preferences in the expected way:
You can use the Java Preferences API.
You can write a Properties file containing the preferences to an OS-appropriate user-writable directory.
On Windows, you could use a Windows-specific API to store the preferences in the Windows registry, except that this makes your application Windows dependent. (I can't see any real advantage in doing this, but I am not a Window expert.)
When you wrap your app up as a JAR file, your properties file will be one (possibly compressed) file within that JAR, and it would be a bad idea to try to write to your own JAR.
getResourceAsStream() is meant to open resources for reading, and these can be anywhere on the classpath. You can't write to URLs or inside JARs, you can only write to files, so it doesn't make sense to give you the same API for output.
Find yourself a directory you're allowed to write into, and write your properties there.
It may be a good idea to copy your properties from your installation classpath (possibly inside a JAR) directly out to a file if it doesn't yet exist, as a first operation upon application startup. This will give you a properties file you can write to, yet the master copy of this properties file will come from your project deliverable.
It sounds like you want to store user preferences. Consider using the Java Preferences API for that.
In addition to Carl's answer, if you're going to read and write to this file frequently, and expect that your application will expand in scope, consider whether to go one step (or several steps) further and use a file-based database like SQLite. There are a few JDBC wrappers for SQLite that would allow you to go beyond the basic string key-value lookup that the Java Properties interface provides.
even though writing the file into resources is not good practical, we still need to do it when our application only run in IDEA locally without deployment, then we can do it as below:
URL resource = Thread.currentThread().getContextClassLoader().getResource("settings.properties");
String path= resource.getPath();
OutputStream outputStream = new FileOutputStream(path);
//outputStream write
I have a Web Start application which needs to save a single text file. I would like to know where I should write the file, such that it goes in a tidy place regardless of the platform it runs on.
If I get my filepath like this...
new File(System.getProperty("user.dir") + System.getProperty("file.separator") + "test.txt);
... then the file gets written somewhere nice and inconspicuous on Linux, but on the desktop on Windows, alongside the icon I'm running the program from, and that's not ideal because the user shouldn't necessarily need to know or care that the file exists.
Is there a good, platform-independent way of getting a file path that allows me to save a file somewhere discreet? I don't much care where it ends up, providing it's not in full view on the desktop.
Thanks.
Neil
user.dir is the current working directory; use user.home instead and java.io.tmpdir for temporary files.
Here's the list of predefined properties for Java 1.5.
What about using a .yourapp directory under user.home instead? You shouldn't face any permission problem, a windows user won't really notice it, it would be hidden on GNU/Linux.
For temporary stuff, you may prefer java.io.tmpdir but keep in mind that the content of this directory (/tmp on GNU/Linux) might be wiped out upon reboot (e.g. with Debian distros). So this is really for temporary stuff.
PS: I prefer to use File.separator over System.getProperty("file.separator").
I strongly suggest using the PersistenceService.
If you don't need the file per user or to be incredibly permanent you can use System.getProperty("java.io.tmpdir"));
As others have stated, "user.home" is a decent choice. If you can get away with it, Preferences are another good choice for storing certain things.
If you do end up using something like "user.home" then make sure you have a fallback position. I've been in many situations where a user's home directory was not writable (locked down windows installs under a domain server for example).
If you store data in the "user.home" directory then put it under a ".myApp" style sub-directory and first verify that you can create that directory. If you cannot create that directory then you could always prompt the user for a place to store it. And then store that location in a system Preference so that it's known the next time the app is run.
On the Mac OS, from what I understand you're suppose to store information in "/Library/Application Support/Your App Name" if the files are to be read by everyone. However when it comes to writing, this is an admin only folder.
Therefore, if you want to write data, you need to store it to "~/Library/Application Support/Your App Name". Notice the "~" at the front. When you do this, each user will have their own data for the app, and be able to read and write.
In Java, if I do new File("~/Library"), this does not work as expected. It just adds "~/Library" to my current folder. Instead what I'd like it to do is return "Users/myAccount/Library". I understand that it's suggested you store files there.
The question is how do I create a File object in Java to point to this folder?
Java, in its typical "why use one character when you can use forty" style, lets you access the "~" directory via System.getProperty("user.home").