Add files in jar during runtime - java

Project is to create exe file. If we run exe file it will open one admin page (designed in Swing) that page contains browse button, max install, max install sys, and create build, while click the browse button we need to select one exe file from system and that file need to save it inside one folder of jar file. The maxinstall, max install sys value is stored in SQL lite database. This admin page will open for first time only,to get condition from admin. Next if we run the exe file it must check maxinstall and all parameter and then install that selected exe file.
My problem is, I created jar from my java program. While running the jar each time, the admin page only opening (i.e) the database file is not updated inside jar, but its works fine in eclipse. After that I need to create jar to exe.

..it is possible to extract jar in runtime,addfile in the extracted jar and create a new jar in runtime..?
Most JREs will place a file lock on the Jars. Therefore they cannot be updated while the JRE is running. Check a sub-directory of user.home for an altered version of the resource. If it is not found, use the one in the Jar. If it is altered, save the changed data to the sub-dir.
Use a sub-directory based on the package name of the main class, to help avoid overwriting the resources of another app. (or other apps. over-writing your resources).

I think that I understand your problem. Your application stores its state into its own jar file. the fact that you are using SQLite etc. does not matter. It works from Eclipse because in this case the class files and resources are not packaged into archive and your program changes files on file system easily.
The answer is: yes, you can change jar file programmatically. Jar is just a zip. You can use ZipInputStream, ZipOutputStream, JarInputStream, JarOutputStream to modify any zip including your own.
But it is very very not recommended for too many reasons. The right solution is to separate your data from your application. You have to store runtime data on file system, DB etc. For example you can create files in user home directory. It is platform independent. You can also use Preferences class that has portable implementations for all platforms.
Yet another reason to do this is your requirement to create exe. OK, you can change jar file but once you created exe file from your jar you cannot change it anymore.

Once an executable .jar is created it will be "locked". I you add more files to a locked .jar, those files will not be recognized internally by the .jar itself at runtime. So, the better approach is to extract your dependent .jar and then add it to a new, executible .jar containing the new file(s) that you need. Then moving forward you can run this new .jar.

Related

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")

How to delete the Executable Jar File by it self?

I developed a simple java application ,is it possiblefor the application (Executable Jar File) to find its current path and delete it self from both the current place and from Recycle Bin after a certain time.
No, when java runtime starts and uses this jar file, windows prevents it from being deleted. In other operating systems like Linux you can delete files even if they are used.
There are already questions/answers that show you how to get the currently running jar file. Keep in mind, the methods aren't consistent across platforms:
How to get the path of a running JAR file?
Deleting a file in Java is fairly straight forward as well:
import java.io.File;
...
new File("c:\\path\\to\\whatever.jar").delete();
On an operating system that doesn't have file locking, you can simply delete the jar you're running from as it's already loaded into memory. On operating systems that lock files, this may not be possible if the JVM decides to lock the currently executing jar(s).
Windows strictly restricts you from doing this untill the jar is in use
It is something like this :
In Linux you can do it here is How to delete a executing jar file
In order to delete the jar file, I recommend:
Creating a bat/sh file
Run the file
Close the jar file with System.exit method
Within the bat/sh file:
Loop until success deletion
Delete the bat/sh file within itself(unlike the jar file bat/sh file can delete itself)

How to package a jar file along with reference files?

Using eclipse, exporting a runnable jar file is pretty simple when I'm only using the application on my computer. Any files that the program is using (sprite sheets, audio tracks, etc.) only exist on my computer, so sending solely the jar to another machine won't work.
What is the easiest way to package a jar along with all the necessary files so that I could run the program on any machine?
I see from your tags that you are working in Eclipse. I am not sure if this method will work in other IDEs and I don't think it'll work at all if you're doing everything manually (it relies on the compiler automatically copying resources over to the bin folder.
The simplest way (at least what I use) is to define another sourcefolder (I like res).
Then you can just add packages to this source folder and dump the relevant images. Then rebuild your project.
Finally, you can use getClass().getResourceAsStream("package/path/file_name.whatever"); to get your files.
After an export as jar, it should work, even on other machines.
If you don't require the other files to be actual files on the file system (which means you can't use File, FileInputStream, etc) then you can use the resource system. If you put them inside the JAR, you can access them like this:
InputStream fileStream = SomeClassInYourJarFile.class
.getResourceAsStream("/path/to/file.png");
This example would give you an InputStream reading from the /path/to/file.png entry in your JAR file - that is, the "file.png" file inside a folder "to" inside a folder "path".
This does not require the files to be in a JAR file - it can load them from wherever your .class files are stored, JAR or not. If you put them in your source folder, Eclipse will automatically copy them to that place - so the above line would also work if you had a package path.to containing a file called file.png.

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.

Modifying a file inside a jar

I would like to modify a file inside my jar. Is it possible to do this without extracting and re jarring, from within my application?
File i want to modify are configuration files, mostly xml based.
The reason i am interested in not un jarring is that the application is wrapped with launch4j if i unjar it i can't create the .exe file again.
You can use the u option for jar
From the Java Tutorials:
jar uf jar-file input-file(s)
"Any files already in the archive having the same pathname as a file being added will be overwritten."
See Updating a JAR File.
Much better than making the whole jar all over again. Invoking this from within your program sounds possible too. Try Running Command Line in Java
You can use Vim:
vim my.jar
Vim is able to edit compressed text files, given you have unzip in your environment.
Java jar files are the same format as zip files - so if you have a zip file utility that would let you modify an archive, you have your foot in the door. Second problem is, if you want to recompile a class or something, you probably will just have to re-build the jar; but a text file or something (xml, for instance) should be easily enough modified.
As many have said, you can't change a file in a JAR without recanning the JAR. It's even worse with Launch4J, you have to rebuild the EXE once you change the JAR. So don't go this route.
It's generally bad idea to put configuration files in the JAR. Here is my suggestion. Search for your configuration file in some pre-determined locations (like home directory, \Program Files\ etc). If you find a configuration file, use it. Otherwise, use the one in the JAR as fallback. If you do this, you just need to write the configuration file in the pre-determined location and the program will pick it up.
Another benefit of this approach is that the modified configuration file doesn't get overwritten if you upgrade your software.
Not sure if this help, but you can edit without extracting:
Open the jar file from vi editor
Select the file you want to edit from the list
Press enter to open the file do the changers and save it
pretty simple
Check the blog post for more details
http://vinurip.blogspot.com/2015/04/how-to-edit-contents-of-jar-file-on-mac.html
I have similar issue where I need to modify/update a xml file inside a jar file.
The jar file is created by a Spring-boot application and the location of the file is BOOT-INF/classes/properties
I was referring this document and trying to replace/update the file with this command:
jar uf myapp.jar BOOT-INF/classes/properties/test.xml
But with this, it wont change the file at the given location. I tried all the options also but wont work.
Note: The command I am executing from the location where jar file is present.
The solution I found is:
From the current location of jar file, I created folders BOOT-INF/classes/properties
Copy the test.xml file into the location BOOT-INF/classes/properties.
Run the same command again. jar uf myapp.jar BOOT-INF/classes/properties/test.xml
The xml file has been changed in the jar file.
Basically you need to create a folder structure like where the file is located into the jar file. Copy the file at that location and then execute the command.
The problem with the documentation is that, it does not have enough examples as well as explanation around common scenarios.
This may be more work than you're looking to deal with in the short term, but I suspect in the long term it would be very beneficial for you to look into using Ant (or Maven, or even Bazel) instead of building jar's manually. That way you can just click on the ant file (if you use Eclipse) and rebuild the jar.
Alternatively, you may want to actually not have these config files in the jar at all - if you're expecting to need to replace these files regularly, or if it's supposed to be distributed to multiple parties, the config file should not be part of the jar at all.
To expand on what dfa said, the reason is because the jar file is set up like a zip file. If you want to modify the file, you must read out all of the entries, modify the one you want to change, and then write the entries back into the jar file. I have had to do this before, and that was the only way I could find to do it.
EDIT
Note that this is using the internal to Java jar file editors, which are file streams. I am sure there is a way to do it, you could read the entire jar into memory, modify everything, then write back out to a file stream. That is what I believe utilities like 7-Zip and others are doing, as I believe the ToC of a zip header has to be defined at write time. However, I could be wrong.
Yes you can, using SQLite you can read from or write to a database from within the jar file, so that you won't have to extract and then re jar it, follow my post http://shoaibinamdar.in/blog/?p=313
using the syntax "jdbc:sqlite::resource:" you would be able to read and write to a database from within the jar file
Check out TrueZip.
It does exactly what you want (to edit files inline inside a jar file), through a virtual file system API. It also supports nested archives (jar inside a jar) as well.
Extract jar file for ex. with winrar and use CAVAJ:
Cavaj Java Decompiler is a graphical freeware utility that reconstructs Java source code from CLASS files.
here is video tutorial if you need:
https://www.youtube.com/watch?v=ByLUeem7680
The simplest way I've found to do this in Windows is with WinRAR:
Right-click on the file and choose "Open with WinRAR" from the context menu.
Navigate to the file to be edited and double-click on it to open it in the default editor.
After making the changes, save and exit the editor.
A dialogue will then appear asking if you wish to update the file in the archive - choose "Yes" and the JAR will be updated.
most of the answers above saying you can't do it for class file.
Even if you want to update class file you can do that also.
All you need to do is that drag and drop the class file from your workspace in the jar.
In case you want to verify your changes in class file , you can do it using a decompiler like jd-gui.
As long as this file isn't .class, i.e. resource file or manifest file - you can.

Categories