ClassLoader.getResource returns 奇怪的路径(也许)?
ClassLoader.getResource returns odd path (maybe)?
从resources文件夹中加载文本文件等资源时,最常见的做法是使用ClassLoader获取路径:
String path = getClass().getClassLoader().getResource("file.txt").getPath();
然后您可以使用 java 拥有的众多阅读器中的任何一个阅读该文件的内容。但出于某种原因,Paths.get(path)
对路径不满意:
byte[] content = Files.readAllBytes(Paths.get(path))
-> throws java.nio.file.InvalidPathException when executed
ClassLoader.getResource(...).getPath() 正在返回:
/D:/Projects/myapp/build/resources/main/file.txt
Paths.get()
不喜欢。显然 /D
之后的 ':' 是一个 'Illegal char'。 (注意路径好像是对的,文件其实是有的)
是哪个问题导致的? ClassLoader.getResource()
返回的是无效路径还是 Paths.get()
胡作非为?
一段时间后
java 中的路径似乎有多种不同的格式。各种框架似乎并不完全同意什么是对的,什么是错的,因此它们创建和接受的路径之间存在各种差异。
在此示例中,Paths.get()
实际上并不期望路径中的前导斜杠:
/D:/Projects/myapp/build/resources/main/vertex.vs.glsl <- EVIL
D:/Projects/myapp/build/resources/main/vertex.vs.glsl <- OK
我想现在的问题是:如何清理 ClassLoader.getResource()
返回的文件路径以便与 Paths.get()
一起正确使用?它们的两种文件路径格式之间还有其他区别吗?
- “最常见的方法”不一定是最好的:)
- 注意你指的是哪条路径:ClassLoader.getResource() returns a URL, which can have a path 组件。但是,这不一定是有效的文件路径。
请注意,还有一个方法 Paths.get(URI) which takes a URI 作为参数
/D:/Projects/myapp/build/resources/main/file.txt
中的第一个斜杠只是表示这是一个绝对路径:参见 Class.getResource
- 我建议,当您想要读取文件时,您只需使用 ClassLoader.html#getResourceAsStream
Update 回答评论:“那么为什么 Paths.get() 不接受绝对路径?”
Paths.get()
是否 接受绝对路径。
但是您必须传递一个有效的(文件)路径 - 在您的情况下,您直接传递 URL-路径(这不是有效的文件路径)。
- 当你调用:
getClass().getClassLoader().getResource("file.txt")
它returns一个URL:file:/D:/Projects/myapp/build/resources/main/file.txt
- 此 URL 包含架构
file:
- 和有效(绝对URL)路径:
/D:/Projects/myapp/build/resources/main/file.txt
- 你尝试直接使用这个URL路径作为文件路径,这是错误的
- 因此 Paths.get(String,..) 方法抛出
InvalidPathException
要将 URL 路径转换为有效的文件路径,您可以使用 Paths.get(URI) 方法,如下所示:
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
请看一下getClass().getClassLoader().getResource("file.txt")
的结果。这是一个URL。使用 getPath()
然后您只需检索 URL 的路径部分,忽略协议和服务器部分。将路径部分作为文件打开可能在某些情况下可行(在文件语法和 URL 路径语法匹配的简单情况下),但不要在生产代码中这样做。
为什么?当您离开 IDE 并将您的应用程序作为 JAR 或 WAR 交付时,资源将驻留在 ZIP 压缩文件中,并且不会有您可以打开的文件 "file.txt",有只有 JAR 或 WAR 文件中的条目。
正如@TmTron 指出的那样,我也建议使用 ClassLoader.getResourceAsStream()
。这在所有情况下都有效。
从resources文件夹中加载文本文件等资源时,最常见的做法是使用ClassLoader获取路径:
String path = getClass().getClassLoader().getResource("file.txt").getPath();
然后您可以使用 java 拥有的众多阅读器中的任何一个阅读该文件的内容。但出于某种原因,Paths.get(path)
对路径不满意:
byte[] content = Files.readAllBytes(Paths.get(path))
-> throws java.nio.file.InvalidPathException when executed
ClassLoader.getResource(...).getPath() 正在返回:
/D:/Projects/myapp/build/resources/main/file.txt
Paths.get()
不喜欢。显然 /D
之后的 ':' 是一个 'Illegal char'。 (注意路径好像是对的,文件其实是有的)
是哪个问题导致的? ClassLoader.getResource()
返回的是无效路径还是 Paths.get()
胡作非为?
一段时间后
java 中的路径似乎有多种不同的格式。各种框架似乎并不完全同意什么是对的,什么是错的,因此它们创建和接受的路径之间存在各种差异。
在此示例中,Paths.get()
实际上并不期望路径中的前导斜杠:
/D:/Projects/myapp/build/resources/main/vertex.vs.glsl <- EVIL
D:/Projects/myapp/build/resources/main/vertex.vs.glsl <- OK
我想现在的问题是:如何清理 ClassLoader.getResource()
返回的文件路径以便与 Paths.get()
一起正确使用?它们的两种文件路径格式之间还有其他区别吗?
- “最常见的方法”不一定是最好的:)
- 注意你指的是哪条路径:ClassLoader.getResource() returns a URL, which can have a path 组件。但是,这不一定是有效的文件路径。
请注意,还有一个方法 Paths.get(URI) which takes a URI 作为参数 /D:/Projects/myapp/build/resources/main/file.txt
中的第一个斜杠只是表示这是一个绝对路径:参见 Class.getResource- 我建议,当您想要读取文件时,您只需使用 ClassLoader.html#getResourceAsStream
Update 回答评论:“那么为什么 Paths.get() 不接受绝对路径?”
Paths.get()
是否 接受绝对路径。
但是您必须传递一个有效的(文件)路径 - 在您的情况下,您直接传递 URL-路径(这不是有效的文件路径)。
- 当你调用:
getClass().getClassLoader().getResource("file.txt")
它returns一个URL:file:/D:/Projects/myapp/build/resources/main/file.txt
- 此 URL 包含架构
file:
- 和有效(绝对URL)路径:
/D:/Projects/myapp/build/resources/main/file.txt
- 此 URL 包含架构
- 你尝试直接使用这个URL路径作为文件路径,这是错误的
- 因此 Paths.get(String,..) 方法抛出
InvalidPathException
- 因此 Paths.get(String,..) 方法抛出
要将 URL 路径转换为有效的文件路径,您可以使用 Paths.get(URI) 方法,如下所示:
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
请看一下getClass().getClassLoader().getResource("file.txt")
的结果。这是一个URL。使用 getPath()
然后您只需检索 URL 的路径部分,忽略协议和服务器部分。将路径部分作为文件打开可能在某些情况下可行(在文件语法和 URL 路径语法匹配的简单情况下),但不要在生产代码中这样做。
为什么?当您离开 IDE 并将您的应用程序作为 JAR 或 WAR 交付时,资源将驻留在 ZIP 压缩文件中,并且不会有您可以打开的文件 "file.txt",有只有 JAR 或 WAR 文件中的条目。
正如@TmTron 指出的那样,我也建议使用 ClassLoader.getResourceAsStream()
。这在所有情况下都有效。