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
Related
This question already has answers here:
Java images not appearing in JAR file [duplicate]
(4 answers)
Closed 2 years ago.
I couldn't find an answer that works so I had to ask here. I have splashscreen file with the contents
JLabel image=new JLabel(new ImageIcon("./image/risk.jpg"));
And the folder structure looks like this
But for some reason when I go to create a jar file like this
The images don't appear in the jar file. I have looked at many other answers and they don't seem to work. I would greatly appreciate an expert eye to tell me what I am missing. Thanks in advance
new ImageIcon("./image/risk.jpg")
The images don't appear in the jar file
Non sequitur. Whether the image file is in that jar or not is irrelevant; this does not work with jar files, period.
That ImageIcon constructor takes in a file argument. File, here, is to be taken literally: It refers to a path to a file on your actual disk. You go with ., meaning: Current working directory, and thereby have lost all chances at a stable app; current working directory is whatever the JVM got started from and therefore unreliable. Even if you wave a magic wand and solve that problem, the next more pressing issue is that there is no risk.jpg file anywhere - it's an entry in a jar file, which is not, itself, a file. Merely an entry in a jar.
The solution
The solution is not to use that constructor, and instead to rely on java's resource retrieval system:
class MyClass {
public void foo() {
URL url = MyClass.class.getResource("risk.jpg");
}
}
This gets you a URL that represents a resource (could be an actual file, but could also be an entry on disk, the web, from a database, generated on the fly - whatever the classloader is providing. If you didn't mess with custom classloaders, it will always be either a file on disk, or entry in a jar file), and this can also be passed to ImageIcon (it also has a constructor that takes a URL).
This then looks for a file named risk.jpg which is sitting in the same place that MyClass.class is sitting. Whether that is on disk someplace, or in a jar file (so if this is in package com.foo;, you have a jar file with entry com/foo/MyClass.class, and that command would then find the entry com/foo/risk.jpg in the same jar file. You can use a prefix slash to go from the root of the jar: MyClass.class.getResource("/image/risk.jpg") (note, no leading dot!) will look in that jar for entry image/risk.jpg.
Great! Uh, but, that image should be in the jar, right?
Yes, this code will ensure you look in the same place class files are, which is good, but you still need to ensure the build is set up properly. 'let eclipse make a jar' is not a recommended build solution; invest some time in learning maven or gradle. However, if you insist, eclipse should just include them, but put the jpg in a source dir, right next to your java file (eclipse knows that non-java files are to be copied over, and java files are to be compiled).
In other words, if you insist on using eclipse's 'make a jar' as build tool, image has to move into src.
Alternatively, set up a basic maven project, where source is in src/main/java and image files and the like are in src/main/resources, use the maven plugin in eclipse to read the maven based project in, and that works too, if you want these directories fully separated for some reason.
I wrote a little Java app for analyzing .csv files. Now I want to keep reading from and writing to a .txt file, which acts similar to a mini-database. For this purpose I simply added the .txt in my project and used the Files.readString(Path) and Files.write(Path path, byte[] bytes) methods.
When I do this in IntelliJ I have no problems but as soon as I build/export the file with Maven and started with the created launcher the app didn't work because the project structure / file organization isn't the same anymore.
I also tried to just add the .txt file to the exported folder afterwards but even then I couldn't manage to implement a relative path to the file.
I'm still relatively new to programming and it's just a small app so I don't think mySQL would fit my needs. I've also read that I could store the data in a property file but I don't know if that would be the right way to archive what I want. Certainly it must be possible to somehow keep a .txt for reading and writing in your exported project. Does someone have an idea?
If you use a ´*.txt` file for storing, that file cannot be inside the jar because the jar cannot change its contents while running.
You need to put the file somewhere else, either at some dedicated location (let the user choose/configure one), or next to the jar. To figure out your own execution path, you can use
How to get the path of a running JAR file?
Maven is one tricky tool. You need to go to the pom file and add the resource.
Unable to add resources to final jar for maven project in Intellij.
-I hope this helps
Trader
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
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/
This question already has answers here:
I'm trying to export a runnable jar in Eclipse, but I need it to include some other files necessary for running my program
(3 answers)
Closed 8 years ago.
When I run my program from eclipse, it shows up fine, the images from Resources\ show up, as do the sounds from the same place, and the text files are found properly. However, when I export my jar, and copy the resources into it with 7Zip, the images will work, but the sounds and the text files can't be found, even though they're in the same folder, with the same path used to find them in my code. I can fix this by putting a folder next to the jar file named Resources, and put everything in there, but I'd like to know why just putting it in the jar file only worked for the images, and how I can get it to work with the text and audio files as well.
An example to show you what I mean:
File inventory = new File("Resources/inv.txt");
threadpath = "Resources/threads.wav";
enemy1 = new Sprite(new Texture("Resources/miniForestGolem.png"));
When I run it in eclipse, all three work fine, but when I export it, and put the resources folder in the jar file, only the image works.
Edit:
I know how to include my resources, and have done so, I'm asking about how/why some of the resources aren't able to be accessed, even after adding them in.
Ok, from your comments we can infer the difference between executing it from eclipse and executing it from a .jar.
From eclipse: it works, because all that new File(...) find an actual file in Resources/
From the .jar: it won't work, since there is no file in a relative ./Resources/ path from the execution path of the application.
The way to make it work is the next:
Make sure Eclipse recognizes Resources/ as a source folder (right-click on project properties, Java Build Path, and add it as a source path)
Look for a replacement for your API methods that, instead of File objects, use InputStreams. Once you have it, retrieve all your resources as InputStreams taken from the classpath. If you are inside MyClass.java, do this: MyClass.class.getClassLoader().getResourceAsStream("Resources/inv.txt"), etc.
What you have achieved by doing this: instead of File objects built on actual operating system files, you will be retrieving InputStreams read straight from your java application classpath. This way, you can package them into a jar, or into a WEB-INF/classes directory inside a web application, or a library folder in some application servers... wherever you like as long as it is into the application classpath. I would do this if I had to package your application in a portable and usable way.