【问题标题】:ClassLoader.getResource returns odd path (maybe)?ClassLoader.getResource 返回奇数路径(也许)?
【发布时间】:2017-08-20 13:11:47
【问题描述】:

从资源文件夹中加载文本文件等资产时,最常用的方法是使用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 之后的“:”是一个“非法字符”。 (注意路径看起来是正确的,文件确实在那里)

是哪一个导致了问题? 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() 一起使用?它们的两种文件路径格式还有其他区别吗?

【问题讨论】:

    标签: java path classloader


    【解决方案1】:
    1. “最常见的方法”不一定是最好的:)
    2. 注意你指的是哪个路径:ClassLoader.getResource() 返回一个 URL,它可以有一个 path 组件。但是,这不一定是有效的文件路径。
      请注意,还有一个方法 Paths.get(URI)URI 作为参数
    3. /D:/Projects/myapp/build/resources/main/file.txt 中的第一个斜杠仅表示这是一条绝对路径:请参阅Class.getResource
    4. 我建议您在要读取文件时直接使用ClassLoader.html#getResourceAsStream

    更新回答评论:“那么为什么 Paths.get() 不接受绝对路径?”

    Paths.get() 确实接受绝对路径。
    但是您必须传递有效的(文件)路径 - 在您的情况下,您直接传递 URL 路径(这不是有效的文件路径)。

    • 当您调用:getClass().getClassLoader().getResource("file.txt") 时,它会返回一个 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(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
    

    【讨论】:

    • 那么Paths.get()为什么不接受绝对路径呢?
    • Paths.get 返回类型 Path,而不是 String?
    • @LeiYang 对,我已经修正了类型
    【解决方案2】:

    请看一下getClass().getClassLoader().getResource("file.txt") 的结果。这是一个网址。使用getPath(),您只需检索该 URL 的路径部分,忽略协议和服务器部分。在某些情况下(在文件语法和 URL 路径语法匹配的简单情况下)将路径部分作为文件打开可能会起作用,但不要在生产代码中这样做。

    为什么?当您离开 IDE 并将应用程序作为 JAR 或 WAR 交付时,资源将驻留在一个 ZIP 压缩文件中,并且不会有您可以打开的文件“file.txt”,在 JAR 或 WAR 中只有一个条目文件。

    正如@TmTron 指出的,我也推荐使用ClassLoader.getResourceAsStream()。这适用于所有情况。

    【讨论】:

      猜你喜欢
      • 2015-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多