This problem has been bugging me for a while. I have to load a couple files in my java app, and the only way I got working so far looks like this:
URL hsURL;
if(System.getProperty("os.name").toLowerCase().contains("windows")) {
hsURL = new URL("file:/" + System.getProperty("user.dir") + "/helpsets/helpset.hs");
}
else {
hsURL = new URL("file://" + System.getProperty("user.dir") + "/helpsets/helpset.hs");
}
But this is ugly and terrible. For a while I thought I had this working:
hsURL = ClassLoader.getSystemResource("helpsets/helpset.hs");
But that no longer works for some reason (I must have changed something and not noticed. It returns null.
Should I be using getResource() instead of getSystemResource() (if so, why is getSystemResource() static but not getResource())?
I am using eclipse and I have tried including the folder in the build path (classpath) and not including it, it doesn't seem to make a difference.
In the above code snippet, we used the current class to load a file using getResourceAsStream method and passed the absolute path of the file to load. The same method is available on a ClassLoader instance as well: ClassLoader classLoader = getClass(). getClassLoader(); InputStream inputStream = classLoader.
The Bootstrap class loader loads the basic runtime classes provided by the JVM, plus any classes from JAR files present in the system extensions directory. It is parent to the System class loader. To add JAR files to the system extensions, directory, see Using the Java Optional Package Mechanism.
A class is always identified using its fully qualified name (package. classname). So when a class is loaded into JVM, you have an entry as (package, classname, classloader). Therefore the same class can be loaded twice by two different ClassLoader instances.
Java ClassLoader is used to load the classes at run time. In other words, JVM performs the linking process at runtime. Classes are loaded into the JVM according to need. If a loaded class depends on another class, that class is loaded as well.
getSystemResource
is static because it will use the system classloader, which is available statically. (ClassLoader.getSystemClassLoader
)
If your resource is available in the classpath, I would suggest using ClassLoader.getResource()
or Class.getResource
from an appropriate class, e.g.
Foo.class.getResource("/helpsets/helpset.hs");
(ClassLoader.getResource
is "absolute"; Class.getResource
is relative to the package of the class unless you prefix it with a '/'.)
If this doesn't work, please post how your app is configured in terms of the classpath, and where your file is.
EDIT: I usually find the URL less useful than an InputStream
, so I use getResourceAsStream
instead of getResource
. YMMV
You've mentioned several different things here, so let's sort them out.
1) Creating a "file:" URL based on "user.dir"
The "user.dir" property refers to the current working directory -- wherever the user might have been when s/he started the app. Chances are good that files written here will disappear between two runs (because the user might run from a different directory).
The "user.home" property refers to the user's home directory -- which should remain the same between runs.
In either case, use a File object to open files, don't muck around with creating a "file:" URL. You get no benefit, and as you can see, you have to write messy code to access it.
2) Retrieving a resource via the classloader
This is meant to retrieve files that are packaged with your application -- read-only files. As you have seen, there are multiple variants. I prefer using the following, because I assume that a class will want to load a file that's packaged with it.
InputStream in = this.getClass().getClassLoader().getResourceAsStream(fileName);
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