I haven't been working with java for long, so I'm not sure as what else to look for. I hope somebody can point me in the right direction.
Goal: I want to use a look up table, stored as a text file. But I don't want to use absolute paths, as in the end I'd like to pack a release and be able to call it from any location (the text file will be included int the packed release).
Current setup: I put the text file in a folder called "resources" (because from reading tutorials about java, I got the impression, this is where I'm supposed to put it to maintain a better structured project).
In the root package folder I have a class (MainClass.java) that is calling another class (LookUpClass.java) in a subpackage. The folder setup is as followed:
I wrote a method in LookUpClass.java
that is retrieving a certain line from my lookup tables in resources. To retrieve the file and read out a certain line, I used
// Gets respective line from LUT
private static String getLineFromLUT(int line) {
URL url = LookUpClass.class.getClass().getResource("/LookUpTables/LookUpTable1.txt");
File file = new File(url.toURI());
BufferedReader br = new BufferedReader(new FileReader(file));
for (int i = 0; i < line; ++i)
br.readLine();
return br.readLine;
}
In my project structure the "java" folder is marked as "source", while "resources" is marked as, well, "resources".
My test setup is very simple:
public static void main(String[] args) throws URISyntaxException, IOException {
String c = LookUpClass.getLineFromLUT(5);
System.out.println("Color of line 5: " + c);
}
Output:
Color of line 5: 0 0 38
(Which is correct.)
I added the exact same lines to PlotterClass.java
and it works fine, too.
Problem:
Now, If I try the same in MainClass.java
I get an error with url
being null. It seems the resource/resource folder can't be found.
I read through various postings on SO already and tried out several proposed solutions, which all failed so far:
LookUpClass.class.getClassLoader().getResource("/LookUpTables/LookUpTable1.txt")
both callings from MainClass.java
and LookUpClass.java
fail (url
is null).Class c = LookUpClass.class.getClass();
, in Debug mode c is "class.java.lang.Class". I was expecting something like "main.package.com.subpackage.LookUpClass".getResourceAsStream()
, but I didn't understand how to get my (e.g.) 5th line, so I discarded it. I'm willing to read up on this, if it solves my problem though.I have no idea how to solve this problem. And I realize that at this point I'm just trying out things, not even understanding why it could or could not work.
For me, it just seems LookUpClass.java
is run from a different location than MainClass.java
. But the "resources"-folder and respective text file location never change. How can the file be found in one case, but not in the other?
You can get all classpath roots by passing an empty String into ClassLoader#getResources() . Enumeration<URL> roots = classLoader. getResources("");
1) Using packagename.* If you use package.* then all the classes and interfaces of this package will be accessible but not subpackages. The import keyword is used to make the classes and interface of another package accessible to the current package.
Adding a class to a Package : We can add more classes to a created package by using package name at the top of the program and saving it in the package directory. We need a new java file to define a public class, otherwise we can add the new class to an existing . java file and recompile it.
Maven has a standard directory layout. The directory src/main/resources
is intended for such application resources. Place your text files into it.
You now basically have two options where exactly to place your files:
An example for this is a class representing a GUI element (a panel) that needs to also show some images.
In this case place the resource file into the same directory (package) as the corresponding class. E.g. for a class named your.pkg.YourClass
place the resource file into the directory your/pkg
:
src/main
+-- java/
| +-- your/pkg/
| | +-- YourClass.java
+-- resources/
+-- your/pkg/
+-- resource-file.txt
You now load the resource via the corresponding class. Inside the class your.pkg.YourClass
you have the following code snippet for loading:
String resource = "resource-file.txt"; // the "file name" without any package or directory
Class<?> clazz = this.getClass(); // or YourClass.class
URL resourceUrl = clazz.getResource(resource);
if (resourceUrl != null) {
try (InputStream input = resourceUrl.openStream()) {
// load the resource here from the input stream
}
}
Note: You can also load the resource via the class' class loader:
String resource = "your/pkg/resource-file.txt";
ClassLoader loader = this.getClass().getClassLoader(); // or YourClass.class.getClassLoader()
URL resourceUrl = loader.getResource(resource);
if (resourceUrl != null) {
try (InputStream input = resourceUrl.openStream()) {
// load the resource here from the input stream
}
}
Choose, what you find more convenient.
In this case simply place the resource directly into the src/main/resources
directory or into an appropriate sub directory. Let's look at an example with your lookup file:
src/main/resources/
+-- LookupTables/
+-- LookUpTable1.txt
You then must load the resource via a class loader, using either the current thread's context class loader or the application class loader (whatever is more appropriate - go and search for articles on this issue if interested). I will show you both ways:
String resource = "LookupTables/LookUpTable1.txt";
ClassLoader ctxLoader = Thread.currentThread().getContextClassLoader();
ClassLoader sysLoader = ClassLoader.getSystemClassLoader();
URL resourceUrl = ctxLoader.getResource(resource); // or sysLoader.getResource(resource)
if (resourceUrl != null) {
try (InputStream input = resourceUrl.openStream()) {
// load the resource here from the input stream
}
}
As a first suggestion, use the current thread's context class loader. In a standalone application this will be the system class loader or have the system class loader as a parent. (The distinction between these class loaders will become important for libraries that also load resources.)
You should always use a class loader for loading resource. This way you make loading independent from the place (just take care that the files are inside the class path when launching the application) and you can package the whole application into a JAR file which still finds the resources.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With