Extract a directory from a jar - java

I have a jar file that's running, but it needs an exe and a couple dlls with it to work.
To make it convenient for the user, I want to package the folder with the exe and the 2 dlls in the jar, and have it extract it when the jar is ran.
I've read answers like this one, and this one, but I still don't understand how to apply that code to what I need. I understand that a jar file is essentially a zip, but I don't know how I can get the path to the zip, and extract the folder I need from it.
I tried using the code posted here to just extract the exe for a start, but it looks like it's trying to extract the exe from the class (if that makes any sense?)
Does anyone have a code snipped they could share to show how to extract a folder with a certain name from the currently executing jar?
If you guys could help me out I would really appreciate it!

If you want to access the resources from a JAR that is on the classpath at runtime, you simply access the resources from the classpath. So no need to read it via the JAR API. Therefore your first link points to a valid solution.
It may be tricky to use the appropriate classloader. If your resource is in the same folder as a Java class file, this link may help you: How to access resources in JAR file?
URL url = getClass().getResource("path/to/img.png");
or
URL url = MyClass.class.getResource("path/to/img.png");
I think you could access the two files separately and store them to a file. There are also methods to open a stream to copy. Here is a similar question: getResourceAsStream returns null

Related

Packaging an Eclipse Program With External Files

I'm not sure if this was answered previously, I tried searching for the kind of question I am asking, but I couldn't find something satisfactory. If someone could point me to a similar question, that would help.
What I am trying to do is to package an eclipse program that has external files, such as images, into a single file, rather than a jar file and the supporting files placed in the same directory.
I am not sure if that is even possible, but is there some way in eclipse that would allow you to somehow package the external files along with the jar file in a single, neat file that can be executed easily?
EDIT:
Thanks to ortis and Thorbjørn Ravn Andersen, I figured out how to do it. Here are the steps for working it out:
Firstly, ensure that all of your external files are in your src folder, not in your bin or workspace or whatever else. If you have packages in your project, they will appear as folders and the external files must be placed into those folders for use within that package.
As for calls to the external files, don't do something like this:
Image img = new Image("fileName");
Rather do this:
Image img = new Image(getClass().getResourceAsStream("fileName"));
while ensuring that "fileName" is in the src folder or package folder, if you have packages.
Some points:
-If you are initializing a global variable using a file name that is outside of your main constructor or function call, getClass(), won't work. Use:
yourClassName.class.getResourceAsStream("fileName");
-if your using JavaFX Scenebuilder and you need to package your external CSS file, here is a solution that will help you load the style sheet in your program instead of using the .fxml file to do it.
-An InputStream variable can be assigned the result of
getClass().getResourceAsStream("fileName"));
and be used instead of the whole mess.
Yes. You must reference all external files as inputstreams instead (because you want the classloader to get them from inside a jar file), and then wrap the resulting single jar file as an EXE file using http://launch4j.sourceforge.net/

Java cannot save to a resource folder with jar

I am writing a program which is dependent on saving to a resource folder that is exported with the jar. I have a source folder titled "resources/inputs" and it exports correctly. I can load from it which is great, but the problem is, when I use:
getClass().getResource(path);
I cannot save to the path returned. I need to be able to save to it and I was wondering, is there any way I can save to this resource folder (or to some other folder existent in the same directory as the jar) no matter where the user has saved the jar file?
The error I get is a FileNotFoundException and the background I've read on it is that since jar triggers java "read-lock" you can only ever read from a jar and can never write to it? Not sure if that is accurate or not, but if it is, how can I work around this using an external folder?
I've never tried this, but its probably having a hard time because the you need to use specialized classes to access files within a jar file (which is a zip file with a different extension). Google "JarEntry" and see if that points you in the right direction.
Does this answer your question

Can you store data inside a .jar?

I'm learning java and am currently trying to develop a simple application. My question is can you store data about settings, etc in a text file internal to a .jar? If so how would you go about accessing this within java? Sorry if this is a really stupid idea.
InputStream is = this.getClass().getResourceAsStream("/data/file.txt");
The resources you are getting need to be on the classpath
Yes you can, and it's not a stupid question we all need to start somewhere.
There are two parts to your question:
Adding a data/text file to a .jar - (using ant to jar it:) add "fileset dir=..." to the jar target, where dir is set equal to the directory that has the data/text file. Refer to How can I include data text files in a jar using Ant?
Accessing that data/text file from within the java code - you need to use a ClassLoader and getResourceAsStream. Refer to Loading files in JAR in Tomcat using getResourceAsStream
Also, please take a look at https://github.com/gitjonathan/turbo-sansa, I have a working version up on it.
Can you store data inside a .jar?
Read-only data can be stored inside a JAR file. You can read such data using getResourceAsStream(...) if the JAR is on the classpath, or by using the standard JAR file API class if it is not on tle classpath.
But storing update-able data in a JAR file is problematic:
In a lot of circumstances it is impossible; e.g. because the JAR file is read-only or was downloaded on the fly.
In all other cases it would be very awkward, because the standard JAR file API class does not support update in place. (You would need to create a new ZIP file, copy across the old content apart from the file you are updating, add that file, and then rename the resulting file.)

Load all files from directory using .getClassLoader().getResource()

In one of my JUnit tests, I am trying to load all the files contained in a directory. I used .getClassLoader().getResource("otherresources") to find the directory. I then made a new java.io.File. I then used listFiles() to get all the children files and then used .getClassLoader().getResource() again to load each of those files.
URL url = FileLoadTest.class.getClassLoader().getResource("otherresources");
File directory = new File(url.getPath());
File[] files = directory.listFiles();
Basically, I want to be able to load all the files in a directory without knowing exactly what they are.
I can properly run the test in Eclipse. When I go to build the project with Maven (mvn install) or run the test case by itself using surefire (mvn -Dtest=FileTest test) the test case fails with a NullPointerException. I think the issue has something to do with the File api not working as intended within the JAR file that the resources are deployed to.
Any tips on how to fix this?
Correct, the File API can only read from the file system, and not within JAR files.
Unfortunately, there's not a good way to do exactly what you're trying to do, without using some additional libraries that utilize some hacks in an attempt to accomplish just this. Resources on the classpath are not meant to be enumerable, as there is no guarantee where they are loaded from (could be from disk, in a JAR file, HTTP, a database, or other exotic resources - including ones where the enumeration of available files would not be feasible). The best approach is to include an "index" or other similar file with a well-known name, which can be referenced to find other resources you're interested in.
One of these "hacks" would be, if you know the path to the JAR file(s), you could read from them using JarFile (or even just ZipFile).
.getClassLoader().getResource("otherresources")
Untested. Once you have the 'directory', use it to get back to the archive itself.
Establish a ZipInputStream to the archive.
Call getNextEntry() until null and add the entries matching the required location to an expandable list (e.g. ArrayList).
Construct an URL from the location of the archive and ZipEntry.getName()
Of course, I would normally suggest creating a list of the target resources when making the archive, then including that list at a known location in the archive. But the above might suffice for this use case.

Using other documents outside a jar file

I just realised that I cant use files from outside a jar archive. If thats the case then when I deploy apps that need other documents, say an xml file, do i send the xml alongside the app or there is a way out..
Thanks
I'd suggest that you simply include the required resources within the .jar file. You can have any type of files in there, including .xml-files.
Related questions:
How do I create a jar file, which includes xml and html files?
How do I read a resource file from a Java jar file?
adding non-code resources to jar file using Ant
How to bundle images in jar file
If you really prefer to load "external" files you'll have to be more clear about the problems of opening them outside of the jar file.
But this does not work if you also want to "write" to one of those files!!! If you only want to read, put everything in there. The convention is to create a package called resources in the root of you source code ("src" for example (I use Eclipse)), and just put everything in there, and then use class.getResourceAsStream(). But if you want to write to a File, for example you want persistence for User's options or other stuff, you're gonna need to write from within the .jar, to a File outside the jar, which has a lot of permission considerations and stuff, but It's possible. use System.getProperty("java.class.path"), and you can write files just next to your jar File...

Categories

Resources