5

When loading an asset such as a text file from the resources folder, the most common approach is to use ClassLoader to get the path:

String path = getClass().getClassLoader().getResource("file.txt").getPath(); 

You can then use any of the many readers that java has to read the content of that file. But for some reason, Paths.get(path) is not happy with the path:

byte[] content = Files.readAllBytes(Paths.get(path)) -> throws java.nio.file.InvalidPathException when executed 

ClassLoader.getResource(...).getPath() is returning:

/D:/Projects/myapp/build/resources/main/file.txt 

Paths.get() doesn't like it. Apparently the ':' after /D is an 'Illegal char'. (Note that the path seems correct, the file is actually there)

Which one is causing the problem? Is ClassLoader.getResource() returning an invalid path or is Paths.get() acting up over nothing?


Some time later
It seems that there are multiple different formats for paths in java. The various frameworks don't appear to completely agree on what is right and what is wrong, therefore there are various discrepancies between the paths that they create and accept.

In this example, Paths.get() was in fact not expecting the leading slash in the path:

/D:/Projects/myapp/build/resources/main/vertex.vs.glsl <- EVIL D:/Projects/myapp/build/resources/main/vertex.vs.glsl <- OK 

I suppose that the question now is: How do I sanitise file paths returned by ClassLoader.getResource() for use with Paths.get() properly? Are there any other differences between their two file path formats?

2 Answers 2

6
  1. "the most common approach" is not necessarily the best :)
  2. Take care which path you mean: ClassLoader.getResource() returns a URL, which can have a path component. However, this is not necessarily a valid file-path.
    Note, that there is also a method Paths.get(URI) which takes a URI as parameter
  3. The first slash in /D:/Projects/myapp/build/resources/main/file.txt just means, that this is an absolute path: see Class.getResource
  4. I recommend, that you simply use ClassLoader.html#getResourceAsStream when you want to read a file

Update to answer comment: "So why does Paths.get() not accept the absolute path?"

Paths.get() does accept absolute paths.
But you must pass a valid (file-)path - and in your case you pass the URL-path directly (which is not a valid file-path).

  • When you call: getClass().getClassLoader().getResource("file.txt") it returns a URL: file:/D:/Projects/myapp/build/resources/main/file.txt
    • this URL consists of the schema file:
    • and the valid (absolute URL)path: /D:/Projects/myapp/build/resources/main/file.txt
  • you try to use this URL-path directly as a file-path, which is wrong

To convert the URL path to a valid file-path you could use the Paths.get(URI) method like so:

URL fileUrl = getClass().getClassLoader().getResource("file.txt"); Path filePath = Paths.get(fileUrl.toURI()); // now you have a valid file-path: D:/Projects/myapp/build/resources/main/file.txt 
Sign up to request clarification or add additional context in comments.

3 Comments

So why does Paths.get() not accept the absolute path?
Paths.get returns type Path, not String?
@LeiYang right, I've fixed the type
0

Please, have a look at the result of getClass().getClassLoader().getResource("file.txt"). It's a URL. With getPath() then you just retrieve the path part of that URL, ignoring protocol and server part. Opening the path part as a file might work under certain circumstances (in the easy cases where file syntax and URL path syntax match), but don't do it in production code.

Why? When you leave your IDE and deliver your application as JAR or WAR, the resources will reside inside a ZIP-compressed file, and there will be no file "file.txt" that you can open, there's only an entry in a JAR or WAR file.

As @TmTron pointed out, I also recommend to use ClassLoader.getResourceAsStream(). That will work in all cases.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.