The getResourceAsStream-method returns null whenever running the executable jar in a directory which ends with a exclamation mark.
For the following example, I have a Eclipse project the following directory structure:
src\ (Source Folder)
main\ (Package)
Main.java
res\ (Source Folder)
images\
Logo.png
I'm reading the Logo.png as follows:
public static void main(String[] args) throws IOException {
try (InputStream is = Main.class.getClassLoader().getResourceAsStream("images/Logo.png")) {
Image image = ImageIO.read(is);
System.out.println(image);
}
}
See the attachment for 2 test cases. First, the executable jar is started from the directory "D:\test123!@#" without any problems. Secondly, the executable jar is started from the directory "D:\test123!@#!!!", with problems.
Are directories ending with an exclamation mark not supported? Is the code wrong?
Thanks in advance.
It means there is a problem with the build path in your project. If it is an android project then it mostly means the target value specified in project.
The exclamation mark (!), known informally as a bang or a shriek, is used at the end of a sentence or a short phrase which expresses very strong feeling. Here are some examples: What a lovely view you have here! That's fantastic!
A simple work around for Windows is to use "\" instead of "/" in the path. That would mean the "!/" character sequence is found after the full path. For instance:
new URL("jar:file:\\d:\\test1231@#!!!\\test.jar!/images/Logo.png");
My Code:
File jar = new File(jarPath + "/" + jarName);
URL url = new URL("jar:" + jar.toURI() + "!" + dataFilePath);
InputStream stream = null;
try {
stream = url.openStream();
} catch (FileNotFoundException e) {
// Windows fix
URL urlFix = new URL("jar:" + jar.toURI().toString().replace('/', '\\')
+ "!" + dataFilePath);
stream = urlFix.openStream();
}
I use toURI() because it handles things like spaces.
Fixes:
The fix itself would be for Java to check if the file exists and if not continue to the next separator (the "!/" part of the url) until the separators are exhausted, then throw the exception. So it would see that "d:\test1231@#!!" throws a java.io.FileNotFoundException and would then try "d:\test1231@#!!!\test.jar" which does exist. This way it does not matter if there are "!" in the file path or in the jar's files.
Alternatively the "!/" can be switched to something else that is an illegal file name or to something specific (like "jarpath:").
Alternatively make the jar's file path use another parameter.
Note:
It may be possible to override something, swap a handler, or change the code to open the file first then look inside the jar file later but I have not looked.
Probably because of this bug or any of the many similar bugs in the Java bug database:
http://bugs.sun.com/view_bug.do?bug_id=4523159
The reason is that "!/" in a jar URL is interpreted as the separator between the JAR file name and the path within the JAR itself. If a directory name ends with !, the "!/" character sequence at the end of the directory is incorrectly interpreted. In your case, you are actually trying to access a resource with the following URL:
jar:file:///d:/test1231@#!!!/test.jar!/images/Logo.png
The bug has been open for almost 12 years and is not likely to be fixed. Actually I don't know how it can be fixed without breaking other things. The problem is the design decision to use ! as a character with a special meaning (separator) in the URL scheme for JAR files:
jar:<URL for JAR file>!/<path within the JAR file>
Since the exclamation mark is an allowed character in URLs, it may occur both in the URL to the JAR file itself, as well as in the path within the JAR file, making it impossible in some cases to find the actual "!/" separator.
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