Java Game refering to files - java

I have started getting into game programming.
My question is, that when I am working with files, either parsing data, writing to files, etc. Should I be using relative path names, or absolute pathnames, or something else which is better. I've heard about using jar files, but I am not sure
1. how that works
2. if it is a good way to do it.
So when developing a game that will be cross platform, what is the best method for managing files that the program will need to read from and write to.

there are several ways in which you can ship your code as a product. the most common are
packaging everything in one executable jar file.
having a set of folders where you place all necessary resources.
minecraft, for example, is written in java and distributed as a single executable jar file that contains all necessary class files and resources. to run the game (assuming you have java installed) all you need to do is double-click the jar file.
read this short tutorial about how to add a main class to a jar file.
either way, always treat classes and resources in your code as if they're in your classpath. for example, if you have a my.properties file on the root of the source tree then load it by using 'my.properties'. if you put it under a 'conf' folder then use 'conf/my.properties'.
i think it is the safest way not to get lost.
are you using maven?

The jar file is a zip of all your compiled *.class files and your resources. You can safely load your resources and even default data FROM a jar if you package your program, but you can NOT safely write data back to the jar. This detail is answered in depth already at
How can an app use files inside the JAR for read and write?
For information on how to package a jar see
http://docs.oracle.com/javase/tutorial/deployment/jar/

Related

How do I organize and access external files nicely in IntelliJ?

I'm programming using IntelliJ IDEA. I'm programming a game. This game needs to save its data inside some files (for example player data, world map exploration data etc.). The problem arises when I want to separate my development environment from the exported .jar executable. When referring to a file in my project, I use a path like "saves/world1/players/player1.data". This file is accessible by using File("saves/world1/players/player1.data"). However, the more files I need, the more my project gets cluttered, because all the files are added into my project root directory. Also, when exporting the .jar artifact, it only exports the .jar file and I have to copy all the other files manually into the same directory as the .jar file. How do I automate this process and how do I organize the files a little better (like putting them in one directory to not clutter my project root folder)? Also, I should mention that I use Kotlin, but I don't this it's important for this question. A Java solution might work just as well.
Have you application declare a file path property from where you load these large external data files. For local dev/testing this can default to a path local to your project but for deployment you'd perhaps have start or execution scripts which allow the user to configure where there '.data' file located.

Reading and writing files within Jar

I have finally completed a program in Java and I have to upload it.
The problem is that I have to upload also the executable .jar file and not only the eclipse project.
The main functionality of my program consists by reading and writing .xml files (for example one file is used to read and add new users), and the files in the project folder are so located:
-Project Name
src
default package
main and all other classes
file1.xml
file2.xml
So the two .xml files are in the root of the project.
My question is: It is better to save the .xml files in the JAR and then writing and reading them from the executable program or it is better to store them in a folder outside the .JAR and reading and writing them as externally files?
It is a good practice to create a folder like that?:
-ProjectName
file1.xml
file2.xml
project.jar
I read in Stackoverflow a lot of people having my same issue and a lot of people doesnt know how to manage this problem properly.
Thank you in advance for the reply :)
Changing files in JAR-files can have all sorts of problems. That starts with simple things such as what should happen when you want to update your program to the newest version? Usually you'd just swap the jar, but then you loose everything you edited so far. You'd need a process to update inside the jar.
Other problems include that for changing the jar file you need to open it, possibly realign contents and rewrite the index which could conflict with the JVM that is reading the jar at the same time causing odd behaviour. On some systems (windows...) the Jar file might even be locked while the application is running and thus you cannot write to it at all.
I'd suggest that you add "default files" (in case that your files are initially not just empty) to you Jar file that represent the initial state. If the application is started you check if the XML files exist in the some normal writable directory and if they don't just copy the default files to that directory. This allows you to deploy still just a single jar file, but once started the appropriate files will be created.
You may read a XML file located inside the executable Jar but it is not possible to update (write) a XML file located inside that executable Jar file. So the best option would be:-
-ProjectName
file1.xml
file2.xml
project.jar
The jar should be kept read-only, the XML "files" inside the jar should be read using getResource[AsStream] (class path). You can use those resources as templates to create a copy in the user's (or application's) directory/sub-directory. For the user's directory:
System.getProperty("user.home")

Using JAR resource as File in java or scala

I have developed an application that basically searches its resources/runtime directory, looking for .java files.
Having fetched all .java sources, it (together with program arguments) passes their absolute paths to JavaCompiler.
Of course, this approach doesn't work when application is deployed as a JAR package. So the question - how can I work with resource files as with regular files, i.e. pass their absolute path and read them afterwards?
I found some related topics here:
reading the file as a stream
making a resource copy to some temporary file
But what if I don't know names of the files? I seek solution that allows me to search the resources/runtime directory. Moreover, I think making a copy of file somewhere and delete it later on is clumsy solution.
I use combination of Java and Scala (with sbt build system), hence solution Java or Scala would be great.

Serialized files don't work when project is converted to executable jar?

I made my java project into an executable jar using the export to jar option in eclipse. The jar runs as expected, except that it does not use any of the serialized files. I can see that clearly from the GUI. What could be the reason for this problem and how do I fix it ?
I saw this related question - Why does my JAR file not create a serialization?
But it does not tell me exactly how to get around this problem. It looks like you cannot pack a folder into a jar. Why ? Because code could accidentally/intentionally continue to add data into that folder and make the whole jar occupy the hard disk ?
How do I create some kind of structure in which I pack my executable jar and its serialization folder ?
Answering this question:
How do I create some kind of structure in which I pack my executable jar and its serialization folder ?
A common approach is to have a well-defined place to store serialized files, settings, etc, that does not depend on where the program has been executed from. Usually it is user's home directory, or Application Data in case of windows. I used this code to store my application settings:
String home = System.getenv("APPDATA");
if (StringUtils.isEmpty(home)) {
home = System.getProperty("user.home");
}
CONFIG_HOME = new File(home, ".myProgram").getAbsoluteFile();
CONFIG_HOME.mkdirs();
So on windows it will use AppData and on *nix systems it will use user's home. The dot in front of myProgram is to make it hidden on *nix platforms, which is a common practice.
EDIT For your question in your comment:
on my linux machine there is no APPDATA env variable so this code will create a directory /home/myUser/.myProgram. On windows it will be something like c:/Users/myUser/AppData/Local/.myProgram. On MacOSX, no idea.
You need your JAR to use the same path for reading the Serialized Files as your code in eclipse.
So you make a properties file containing the directory with your serialized objects.
Then, this is the same for both your JAR and our project.
See also: http://www.mkyong.com/java/java-properties-file-examples/
You can use
AClass.class.getResource(String str);
//or
AClass.class.getResourceAsStream(String str);
AClass: one of your classes.
str: file location which you want to read.
For example;
if your class hierarchy seem like this:
+src
+-com
+-test
|-AClass.java
+-util
+-PrintUtil.java
+-resources
|-Bouble.png
|-Mouse.png
+-Ocean.png
and for reading "Mouse.png" image, you can this with a lots of ways:
AClass.class.getResource("/resources/Mouse.png");
//or
PrintUtil.class.getResource("../resources/Mouse.png");
...
You can't write inside a jar file while you are using/running the jar file. When you put the jar file in you classpath or you run the program from jar directly, the jar will be locked by your jvm, hence it won't allow you to update the same jar file which you are currently using.
The solution given by people which says use resource as stream will work if your classes are there in a folder, not in an archive (which you are using).
As an archive you can't directly update it, you need to do following steps (by yourself or by 3rd party api),
Extract in temp location
update the files
re archive
Now as the jar file is locked, you won't be able to do the third operation, which is not even safe. As an example when you are running a jar file, try to rename it, it won't happen, if it happens, the jar file is not yet locked by the jvm, it gets locked whenever you call a class which is inside the jar file.
For better and secure serialization and file saving please look into this: java.util.prefs.Preferences.

How can I export my program in an executable format (Java, eclipse)?

I have created a program in Java using eclipse that contains a couple of folders with graphics and files that get read from and written to. What I need is a way to export the whole program in some executable format so that anyone can run my program.
I've had a look around online and I notice that people suggest creating an executable JAR file. However I have my reservations about this since I suspect it will choose to ignore the graphics & other files that the program uses, only focusing on the actual source code.
Please could someone suggest a solution to this issue, it is absolutely essential that the files and graphics are packaged up with the rest of the code.
On another related note; at present I'm referencing the files & graphics using files paths that are specific to my computer. If I were to use another solution such as creating an installable program how should I handle these filepaths? Apologies if this is a naive question, however I'm new to this sort of thing.
However I have my reservations about this since I suspect it will choose to ignore the graphics & other files that the program uses, only focusing on the actual source code.
When you think you may have a solution but it doesn't work, you should test that theory.
A jar file is absolutely the right solution for this. However, you need to make sure that Eclipse considers them as resources on the build path so that it will copy them into the jar file. Then you just need to refer to them from the jar file:
On another related note; at present I'm referencing the files & graphics using files paths that are specific to my computer. If I were to use another solution such as creating an installable program how should I handle these filepaths?
Use Class.getResource() or Class.getResourceAsStream() or the ClassLoader equivalents. That will let you load your resources directly from the jar file, without even having separate files on the file system.

Categories