I'm working on a browser based applet game, and I intend to store the top ten scores in a text file in the directory with the JAR file. How would I read and write to a text file if it's outside the JAR file?
As far as I know the only way to do this is via the JNLP persistence service
A signed applet (jar, JNLP) has the same disk IO permissions as the user running the applet.
Otherwise, javax.jnlp.PersistenceService is your best bet.
Related
I know that .jar files are basically archives as well as being applications. What I'm asking is how can I store data(actual files not just strings) packed inside my program? I want to do this within my Java code.
The reason for this if your wondering is that I'm producing a server mod of a game. The server starts and creates all the level data and I want to store all these file inside my .jar app.
Yes you can do this.
Non-code resources in a JAR file on the classpath can be accessed using Class.getResourceAsStream(String). Applications routinely do this, for example, to embed internationalized messages as resource bundles.
To get your file into the JAR file (at project build time!), just copy it into the appropriate place in the input directory tree before you run the jar command. Build tools such as Maven, Gradle, etc can automate that for you.
Is there a way to add files to the archive within the app?
In theory, your application could store files inside its own JAR file, under certain circumstances:
The JAR has to be a file in the local file system; i.e. not a JAR that was fetched from a remote server.
The application has to have write access to the JAR file and its parent directory.
The application must not need to read back the file it wrote to the JAR in the current classloader; i.e. without exiting and restarting.
The JAR must not need to be be signed.
The procedure would be:
Locate the JAR file and open as a ZIP archive reader.
Create a ZIP archive writer to write a new version of JAR file.
Write the application's files to the writer.
Write all resources from the ZIP reader to the writer, excluding old versions of the applications files.
Close the reader and writer.
Rename the new version of the JAR to replace the old one.
The last step might not work if the initial JAR is locked by the JVM / OS. In that case, you need do the renaming in a wrapper script.
However, I think that most people would agree that this is a BAD IDEA. It is simpler and more robust to just write regular files.
The other answers have provided some good strategies, but I am going to suggest going in a somewhat different direction.
This game supposedly has graphics and is a desktop application. It is most easy to distribute desktop applications from a web server.
If both those things are true of your game, then look into using Java Web Start to deploy it.
JWS offers APIs not available to other apps. & one of particular interest to this problem is the PersistenceService. The PersistenceService allows for small amounts of data to be stored and restored by an app. (even when it is in a sand-box). I have made a small demo. of the PersistenceService.
The idea would be to check the PersistenceService for the application data, and if not found, use the data in the Jars. If the user/application alters the data, write the altered data to the PersistenceService.
JWS also offers other nice features like splash screens, desktop integration, automatic updates..
This is not possible. You however can look into embedded databases for your usecase. Java 6 comes with JavaDB. If you doesn't want to use it then you can find more here http://java-source.net/open-source/database-engines
I would recommend that you consider having two JARs: one to store your application's class files and another JAR to store the user data. If you do not have two separate JARs, then you will have difficulties obtaining a write lock from the Operating System (since you would be trying to overwrite the JAR containing your program while java is reading it).
To create a JAR, use the java.util.jar.JarFile class. There is also another question on stackoverflow which describes how to create/write a JAR file.
Don't do this. A jar file is a source of application classes and resources, not a file system. You wouldn't try to save files into a exe, would you?
By creating a file in the Source Packages (ex: /src/resource/file.txt) its contents can be read using Class.getResourceAsStream(String)
This is a working implementation of the following answer
InputStream is = Class.class.getResourceAsStream("/resource/file.txt");
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
StringBuilder sb = new StringBuilder();
String line;
while((line = br.readLine()) != null) {
sb.append(line).append("\n");
}
System.out.println(sb.toString());
I am making the setup of java swing application by using Inno Setup as an exe i am selecting the jar file of my project, I am also adding other necessary resources as folder.
When I am installing the setup on the client side. it is putting the jar and other
resources in program files folder but there client can extract the my java classes
and other resources from jar. I want that client can only use the resources by
application program but he could not extract the resources. How is it possible?
There is literally nothing you can do to entirely prevent someone from extracting the resources.
The best you can do is to make the process a bit difficult; e.g. by storing the resources in the JAR file in encrypted form. The problem is that your program would need to decrypt the resources in order to use them. Someone with sufficient skills and patience can reverse engineer your decryption code and capture the unencrypted resources.
By the way, this is not a Java-specific problem. Any application that you provide to a user as an executable can be reverse engineered ... assuming that the user has the wherewithal to run it in the first place.
The bottom line is that if you are not prepared for the possibility that someone might extract the resources, you should not distribute the executable.
I am doing a project in java and in that i need to add and modify my
text file at runtime,which is grouped in the jar.
I am using class.getResourceAsStream(filename) this method we
can read that file from class path.
i want to write into the same textfile.
What is the possible solution for this.
If i can't update the text file in jar what other solution is there?
Appreciate any help.
The easiest solution here is to not put the file in the jar. It sounds like you are putting files in your jar so that your user only needs to worry about one file that contains everything related to that program. This is an artificial constraint and just add headaches.
There is a simple solution that still allows you to distribute just the jar file. At start up, attempt to read the file from the file system. If you don't find it, use default values that are encoded in you program. Then when changes are made, you can write it to the file system.
In general, you can't update a file that you located using getResourceAsStream. It might be a file in a JAR/ZIP file ... and writing it would entail rewriting the entire JAR file. It might be a remote file served up by a Url classloader.
For your sanity (and good practice), you should not attempt to update files that you access via the classpath. If you need to, read the file out of the JAR file (or whatever), copy it into the regular file system, and then update the copy.
I'm not saying that it is impossible to do this in all cases. Indeed, in most normal cases you can do it with some effort. However, this is not supported, and there are no standard APIs for doing this.
Furthermore, attempts to update resources are liable to cause anomalies in the classloader. For example, I'd expect resources in JAR files to not update (from the perspective of the application) until the application restarted. But resources in exploded JAR files probably would update ... though new resources might not show up.
Finally, there are cases where updating a resource is impossible:
When the user doesn't have write access to the application's installation directory. This is typical for a properly administered UNIX / Linux machine.
When the JAR file is fetched from a remote server, you are likely not to be able to write the updates back.
When you are using an arbitrary custom classloader, you've got no way of knowing where the actual bytes of an updated resource should be stored, and no way of storing them.
All JAR rewriting techniques in Java look similar. Open the Jar file, read all of it's contents, and write a new Jar file containing the unmodified contents (and the modifications you whished to make). Such techniques are not advisable for a Jar file on the class path, much less a Jar file you're running from.
If you decide you must do it this way, Java World has a few articles:
Modifying Archives, Part 1
Modifying Archives, Part 2
A good solution that avoids the need to put your items into a Jar file is to read (if present) a properties file out of a hidden subdirectory in the user's home directory. The logic looks a bit like this:
if (the hidden directory named after my application doesn't exist) {
makeTheHiddenDirectory();
writeTheDefaultPropertiesFile();
}
Properties appProps = new Properties();
appProps.load(new FileInputStream(fileInHiddenDir));
...
... After the appProps have changed ...
...
appProps.store(new FileOutputStream(fileInHiddenDir), "Do not modify this file");
Look to java.util.Properties, and keep in mind that they have two different load and store formats (key = value based and XML based). Pick the one that suits you best.
If i can't update the text file in jar what other solution is there?
Store the information in any of:
Cookies
The server
Deploy the applet using 1.6.0_10+, launch it using JWS and use the PersistenceService to store the information. Here is my demo. of the PersistenceService.
Also, if your users will agree to a trusted applet (which seems overkill for this), you might write the information to a sub-directory of user.home.
I'm using the Netbeans IDE, and I'm currently using a GlassFish server.
What I want to do is write to a file.
I looked at some pages, and the code I have now (that is not working as far as I know) looks like:
File outputFile = new File(getServletContext().getRealPath("/")
+ "TheFile.txt");
FileWriter fout = new FileWriter(outputFile);
fout.write("The Content");
fout.close();
This is my project's structure:
Also where will the file get placed?
Edit:
I forgot to mention there are some other folders below the ones in the picture: Test Packages, Libraries, Test Libraries and Configuration Files. However I don't think the file would get placed there.
Edit (newest):
I found out the file is stored in the /build/web folder, but this is not appearing in Netbeans. Even after I restarted it.
As you've coded, the file will be placed in public web root. That's where getRealPath("/") will point to. To be precise, it's the folder named Web Pages as in your screenshot. As an exercise, do the following to figure the absolute path, so that you can find it by OS disk explorer.
System.out.println(file.getAbsolutePath());
I don't do Netbeans, but likely you need to refresh the folder in your IDE after the write of the file so that it appears in the listing in the IDE. Click the folder and press F5. This is at least true for Eclipse.
That said, this approach is not recommended. This won't work when the servletcontainer isn't configured to expand the WAR on disk. Even when it did, you will lose all new files and changes in existing files when the WAR is been redeployed. It should not be used as a permanent storage. Rather store it on a fixed path outside the webapp or in a database (which is preferred since you seem want to reinvent a CMS).
Note that this is in no way guaranteed to work in all web containers or through restarts and will most likely be overwritten by a redeployment.
If you want to be able to allow your user to update content, you need to store the new content somewhere and have a servlet or a JSP-page or a facelet retrieve the new content from the backing storage and send it to the browser.
See the documentation for getRealPath. It returns you the location on the disk for something specified with a URL.
I'm guessing your file is in the root of your web application on the disk within Glassfish (where the WAR file is extracted). I don't know enough about Glassfish to say where that will be.
Also, note you are using string concatenation to create the file name, so if the getRealPath call doesn't return a String with a "/" on the end, then you might be creating a file in the parent directory of your web app. Perhaps best to use a File object for the parent directory when creating the File object for the actual file. Check out the File API.
I'd recommend creating the file outside of your web app. If you redeploy your WAR file then you might delete your file, which probably isn't what you want.
Being in a servlet makes little difference to the fact that you want to output a file. Just follow the standard file APIs as a starting point. Here's a tutorial.
I want to build a simple file uploading applet in Java. It will be used to upload files to a regular linux web server. So if someone went to:
http://site.com/file-upload-applet
And uploaded a file there via the applet, it will be accessible at:
http://site.com/uploads/your-file.jpg
The user should be able to click 'Browse', and then look through the folders on his computer ,and be able to select as many files, or every file in a folder, if he wanted. Then, when he hits upload, he should be shown a progress bar while the files are uploaded.
Any thoughts about this, and how this could be accomplished in Java as an applet? I will just need some pointing in the right direction, such as which Libraries to use.
You'd need to have a signed applet, as unsigned applets do not have access to the filesystem.
I found an article about signed Applets.
As for the other components, you'll most likely need a JFileChooser, JProgressBar, and a JButton (that uses Apache HttpClient's PostMethod with a MultipartRequestEntity that wrape the JFileChooser's file in a FilePart).
I used the Apache Commons File Upload, and it worked like a charm. It took away most of the problems I was worried about, and was very easy to use.