I have completed a program in eclipse and now I would like to export it as a single runnable jar file. The program contains a resource folder with images and text files in it. This is located beneath the source folder.
The res file is not added to the build path however when I run the program in Eclipse it still works.
The thing that is confusing me is that the res file is being saved into the runnable jar file when I export it as I can open the Jar file with WinRar and I see the folder is there with all the objects in it. But when I run the problem it stops at the point that the resource folder is referenced. To add to my confusion when I manually copy and paste the res folder next to where the runnable jar file is saved and run the program it works exactly as it should do.
Now I know this is something to do with how I reference the files in my code. At the moment I have it like this
reader = new LineNumberReader(new FileReader("res/usernames.txt"));
This works exactly how I want and accesses the res folder without any exceptions - in Eclipse and when I move the resource folder next to the Jar file.
I would like it to work normally but without having a folder outside of the Jar file I would like it all encapsulated in one Jar file.
I did a lot of research and what seems to be a common fix - may I add I don't really know how it works but everyone seems to mention it - is to somewhere use:
myClass().getResource()
When I create a new FileReader it needs a String input however when I use myClass().getResource() it returns a resource and not a string. I also don't have a clue how it is meant to reference the resource folder. Should I move the resource folder into the source folder?
Does anyone know how I can reference the resource folder from within the runnable jar file?
Sorry for rambling question I know what I want for my final product but I'm getting confused by the build paths and referencing from within classes and I have searched online for a long time trying to figure it out.
Resources, when you deploy your software, are not deployed as files in a folder. They are packaged as part of the jar of your application. And you access them by retrieving them from inside the jar. The class loader knows how to retrieve stuff from the jar, and therefore you use your class's class loader to get the information.
This means you cannot use things like FileReader on them, or anything else that expects a file. The resources are not files anymore. They are bundles of bytes sitting inside the jar which only the class loader knows how to retrieve.
If the resources are things like images etc., that can be used by java classes that know how to access resource URLs (that is, get the data from the jar when they are given its location in the jar), you can use the ClassLoader.getResource(String) method to get the URL and pass it to the class that handles them.
If you have anything you want to do directly with the data in the resource, which you would usually do by reading it from a file, you can instead use the method ClassLoader.getResourceAsStream(String).
This method returns an InputStream, which you can use like any other InputStream - apply a Reader to it or something like that.
So you can change your code to something like:
InputStream is = myClass().getResourceAsStream("res/usernames.txt");
reader = new LineNumberReader( new InputStreamReader(is) );
Note that I used the getResourceAsStream() method from Class rather than ClassLoader. There is a little difference in the way the two versions look for the resource inside the jar. Please read the relevant documentation for Class and ClassLoader.
Related
I have a class within a Maven project that I am trying to use to get user data and map it to a json file located in another folder outside of the one the compiled jar is located.
My question isn't necessarily how to append data to a json file, but rather how I can get the location of the json file I'd like to append my data too.
Take for instance I have a project with folders like:
Project/src/main/java/com.website.project/Class.java
Once that I have this project packaged into a jar file, I would then place it in a folder where it would be run:
App/jars/Project.jar
I want it to access a json within the folder:
App/json/file.json
What code would I need to write to access the directory from my Class.java?
I am sorry if this was confusing, I'm not the best when it comes to Stack Overflow, but thank you so much for any help in advance!
You could keep your App/json/file.json in src/main/resources folder.
Path - src/main/resources/App/json/file.json
Then you could access it by :
JSONTokener parser = new JSONTokener(this.getClass().getResourceAsStream("/App/json/file.json"));
JSONObject jobj = new JSONObject(parser);
jobj.put("style", style[i]); // If you want to add a new key value or just replace it
The file itself will get packaged in JAR file
Don't forget to include org.json in your pom.xml dependency.
Import this in your class:
import org.json.JSONObject;
import org.json.JSONTokener;
First approach:
Please test if you can find the file with:
File file = new File("./../json/file.json");
System.out.println("File exists: " + file.exists());
Relative paths in java start with ./. When you export your jar the relative start path is the location of the jar => App/jars/ so you need to go one folder up with ../ and after that go inside /json/file.json
The disadvantage of this approach:
To work with file outside your java project (assuming your java project is in java directory) means that you have to create every time this folder structure everywhere. For example in your case if you want to work also in you IDE inside of your workspace of projects you have to add directory json and after that your file.json.
Second approach:
Another solution can be to add your file inside the java project itself. Then you will be able to read your file easy with getClass().getResourceAsStream("file.json");. Consider that file.json is inside your class's package. This way you can test and see 'file.json' also inside your IDE.
The disadvantage of this approach:
Pay attention that if you use your file inside the Java project it will end up in the jar. When this happen you no longer can access it as File. That why I am useing getResourceAsStream method in this case. To read more about this see answer:
https://stackoverflow.com/a/20389418/6068297
Also you have to know that getClass().getResourceAsStream("file.json"); will not work in static methods for example in public static main(String[] arg).
Update:
Also the jar file is meant to be archive so it must stay unchanged. So you can not (you should not) write back changes to file inside the jar. If you need to have some modifiable file then you should create it outside the jar. You can add it relative to the jar location or in a place like home directory of the current user where relevant files to the current user (who is using your application) can be created without some additional permissions.
Third approach:
You mention that you are using Maven project. There is a folder in the Maven project which is called resources => src/main/resources. This folder end up in the classpath so you can also put your file file.json there and read it as second approach with getResourceAsStream. This way you can have clear separation between java classes and other files.
The disadvantage of this approach:
The same disadvantages as in the second approach.
I hope it helps.
I have tried many variants but I cant find correct.
I have something like
Inside my jar, which created by Maven I can see that
That is my folder with classes. And, by the way, If I start my program in IDEA, not from Console, there is not any exception with paths
Here, I am in debug mode start my jar trying to see, where is the problem.
If I do 'file.exists()' it would be false but file inside. I think, that problem because of '.jar!\' in the path, but I don`t know how to remove that.
Anyway I've tried absolute and relative path, I've tried
Thread.getCurrentThread.getContextLoader.getResource()
GUI.class.getResource()
GUI.class.getClassLoader.getResource()
Nothing help
You can't use File to open resources inside a jar file. File can only be used with normal files and directories.
Note: using File works fine within in the IDE, since all files are not packaged in a jar file yet. But the program will break after you package it.
Once you locate the resource eg. URL res = GUI.class.getResource("/rxtx64/myres.dll") , you can open that resource as a stream InputStream is = res.openStream(); .
See also related answers Utils to read resource text file to String (Java) and How to read a text-file resource into Java unit test?
I'm trying to read a txt file that is in a folder called "levels". The class where I'm using the Scanner is in src/anotherPackageName, if that's relevant. When I execute:
Scanner s = new Scanner(new File("levels/level0")); //adding .txt doesn't fix
it throws an exception. I don't want to use an absolute path, but rather relative to the project if possible. This is my folder structure:
D:\OneDrive\Folder\AnotherFolder\ProjectName
ProjectName
src
packageOne
ClassWhereImUsingScanner
OtherClasses
(...)
levels
level0
level1
(...)
So in order to access a file you could do something like this:
FileReader sourceFile = new FileReader("levels/level0.txt");
BufferedReader inStream = new BufferedReader(sourceFile);
String Line = inStream.readLine();
Then, you can use a tokenizer depending on your data and how you want to store it.
You could see this example: http://www.mkyong.com/java/how-to-read-file-from-java-bufferedreader-example/
Bear in mind that in most Java code, the end state of the project is not run from the IDE, but rather from some production system (e.g. an app or a server). In that case, your development source code structure won't be available.
There are two main ways to read text files or other resources in Java: either you can find the path to the actual file, in which case you need to deal with possibly not running out of your development source tree, or else you need to find a way to bundle the text file into your project.
Most Java projects end up getting compiled into some kind of archive, either a JAR file or a WAR file (for web applications) or something like an Android APK. In most cases you can add your own text files into the project archive. (For example, in a Maven project, if you just put your text file in the src/main/resources folder it should be included in the compiled JAR.)
However, in this case, the text file is no longer a separate file on disk, but rather a blob of data inside an archive. You could unzip the archive to get an actual File object, but that's wasteful if all you actually need is to read the bytes.
Thus, the most common way that text files like this are read is by using the existing ClassLoader mechanism, which is what is reading the .class files from disk (or from an archive, or over the network, or whatever). The ClassLoader already knows how to load bytes that are "alongside" your compiled code, so you can just make use of that.
In your case, you should be able to do something like this:
Scanner scanner = new Scanner(
getClass().getResourceAsStream("/path/to/file.txt"));
In this case, the /path/to/file.txt path is relative to the path your class was loaded from. E.g. if your class is named my.package.Foo then the actual class bytes will be in a folder (either a filesystem folder or in a JAR file or something) named my/package/Foo.class -- in this case, the path/to/file.txt and my/package/Foo.class will be relative to the same root.
See the documentation on resources for more information.
Usually the path is relative to your execution, but it also depends on your project setup on eclipse, could you send more information about you directory structure?
Based on you structure try something like this:
Scanner s = new Scanner(new File("../levels/level0"));
Scenario is the following:
Developing a jsp application with jdeveloper
Deploying to Oracle Weblogic
All files are in the same project
Source files are inside packages that are inside the src folder
Inside the Resources folder are two files: menu.json and TestWS.properties
So, I made a java class that should read menu.json and return a menu (in html) based on its structure.
When, inside the class, I do this
InputStream i =
Thread.currentThread().getContextClassLoader().
getResourceAsStream("Resources/menu.json");
BufferedReader r = new BufferedReader(new InputStreamReader(i));
The InputStreamReader constructor throws a NullPointerException, I suppose because it can't find the file.
Funny thing is, if I try to load TestWS.properties instead, it loads it just well.
I tried checking the project's properties, manually added both files under Project Source Path -> Resources, adding the .json extension to Compiler -> Copy file types to output directory, renamed, deleted, recreated, changed extension to the json file, deployed to WAR and loaded the project on another machine running weblogic, but to no avail.
Is there anything else I'm missing?
This is explained in this article.
In short, you have to change the compiler setting "Copy File Types to Output Directory" to include the extension of the resources you want to have available at runtime.
BufferedImage = ImageIO.read(getClass().getResourceAsStream("/Images/player.gif"));
First of all, yes I did add the image folder to my classpath.
For this I receive the error java.lang.IllegalArgumentException: input == null!
I don't understand why the above code doesn't work. From everything I read, I don't see why it wouldn't. I've been told I should be using FileInputStream instead of GetResourceAsStream, but, as I just said, I don't see why. I've read documentation on the methods and various guides and this seems like it would work.
Edit: Okay, trying to clear some things up with regards to what I have in the classpath.
This is a project created in Eclipse. Everything is in the project folder DreamGame, including the "Images" folder. DreamGame is, of course, in the classpath. I know this works because I'm reading a text file in /Images with info on the gif earlier on in the code.
So I have: /DreamGame/Images/player.gif
Edit 2: The line that's currently in the original post is all that's being passed; no /DreamGame/Images/player.gif, just /Images/player.gif. This is from a method in the class ImagesLoader which is called when an object from PlayerSprite is created. The main class is DreamGame. I'm running the code right from Eclipse using the Run option with no special parameters
Trying to figure out how to find which class loader is loading the class. Sorry, compared to most people I'm pretty new at this.
Okay, this is what getClassLoader() gets me: sun.misc.Launcher$AppClassLoader#4ba778
getClass().getResource(getClass().getName() + ".class") returns /home/gixugif/Documents/projects/DreamGame/bin/ImagesLoader.class
The image file is being put in bin as well. To double check I deleted the file from bin, cleaned the project, and ran it. Still having the same problem, and the image file is back in bin
Basically, Class.getResourceAsStream doesn't do what you think it does.
It tries to get a resource relative to that class's classloader - so unless you have a classloader with your filesystem root directory as its root, that won't find the file you're after.
It sounds like you should quite possibly really have something like:
BufferedImage = ImageIO.read(getClass().getResourceAsStream("/Images/player.gif"))
(EDIT: The original code shown was different, and had a full file system path.)
and you make sure that the images are copied into an appropriate place for the classloader of the current class to pick up the Images directory. When you package it into a jar file, you'd want the Images directory in there too.
EDIT: This bit may be the problem:
First of all, yes I did add the image folder to my classpath.
The images folder shouldn't be in the classpath - the parent of the Images folder should be, so that then when the classloader looks for an Images directory, it will find it under its root.
If you use resourceAsStream "/" referes to the root of the classpath entry, not to the root of the file system. looking at the path you are using this might be the reason.
If you load something from some home path you probably should use a FileInputStream. getResourceAsStream is for stuff that you deploy with your app.