Issue
I reviewed a lot of answers on the topic of Java Files and path problems, even some with whitespaces in the path, but non answered my question I'd like to ask:
Why does the following code work, when in a non-whitespace-directory and why does it fail otherwise?
I stripped my problem down to the bare essentials of the question, so I hope anyone can explain the problem to me ;-)
I have an old API that I must feed with the file handles of some images, and I decided to load the images via a relative path URL approach.
I know that this does not work from jars, but I do not intend to load any image from a jar yet. The solution is sufficient for my current requirements and I do not want to turn everything into streams as of now...
But the success of any execution is highly dependent on the directory it is done in! This seems strange to me.
So I wrote a JUnit test and provided some files which are in the test resources directory to research this issue.
└───imageload
├───src
│ ├───main
│ │ ├───java
│ │ └───resources
│ └───test
│ ├───java
│ │ └───stupid
│ │ └───test
│ └───resources
│ └───testset
└───target
├───generated-test-sources
│ └───test-annotations
└───test-classes
├───stupid
│ └───test
└───testset
This is the test code to make the problem obvious:
package stupid.test;
[... imports omitted...]
public class SimpleTest {
public static final File getFileByRelativePathURL(String relativePath) {
URL url = Thread.currentThread().getContextClassLoader().getResource(relativePath);
File file = new File(url.getPath());
return file;
}
@Test
void loadImage() {
File theFile = SimpleTest.getFileByRelativePathURL("testset/black.jpg");
Boolean exists = theFile.exists();
assertTrue(exists);
}
}
When running the test in this directory all works fine:
- D:\Temp\working\imageload\
while running it from here it fails:
- D:\Temp\not working\imageload\
I have had a closer look at the resulting file instances, and the space in the directory is properly escaped to this file object path:
file = D:\Temp\not%20working\imageload\target\test-classes\testset\black.jpg
But there must be a problem with the %20 because the file cannot be found according to the "exists()" method of the File Class.
I hope the problem might be obvious to many of you, while I still expect that "theFile.exists()" returns true in any directory with or without whitespaces.
What am I doing wrong?
UPDATE: I was asked if my question is a duplicate to this article:
Unfortunately the solution does not address my urge to find the proper relative path. Instead it passes an absolute path to the file constructor.
But the combination with the comment by JB Nizet helped me understanding the problem... and although it is a pretty dirty solution I changed my relative URL method to this:
public static final File getFileByRelativePathURL(String relativePath) {
URL url = Thread.currentThread().getContextClassLoader().getResource(relativePath);
File file = new File(url.getPath().replaceAll("%20", " "));
return file;
}
Now everything works fine... stupid me! I really have to do it in another way ;-)
Solution
Thanks to the comment of JB Nizet I came to a solution which is probably more a "dirty hack" then a proper workaround but it is an efficient solution for my current problem.
The original error was my assumption that I could use escaped URL paths as file paths, which is obviously not correct. So I removed the escaping of blanks by modifying my relative path method like this:
public static final File getFileByRelativePathURL(String relativePath) {
URL url = Thread.currentThread().getContextClassLoader().getResource(relativePath);
File file = new File(url.getPath().replaceAll("%20", " "));
return file;
}
This makes real spaces out of the '%20' substitutions and now the JUnit tests work in all paths that contain spaces. It is not a solution for other whitespaces or escaped special characters though.
I will take the advice and try to work around the necessity of File objects in the old API I am using as good as possible!
In my code I will definitely favour Streams! :)
Answered By - LastZolex