ClassLoader.getResource返回奇数路径(可能)?

时间:2017-08-20 13:11:47

标签: java path classloader

从资源文件夹加载资源(如文本文件)时,最常用的方法是使用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()正确使用?它们的两种文件路径格式之间是否还有其他差异?

2 个答案:

答案 0 :(得分:1)

  1. &#34;最常见的方法&#34; 不一定是最好的方法:)
  2. 注意您所指的路径:ClassLoader.getResource()返回一个网址,该网址可以包含path个组件。但是,这不一定是有效的文件路径 请注意,还有一个方法Paths.get(URI),其中URI为参数
  3. /D:/Projects/myapp/build/resources/main/file.txt中的第一个斜杠只是意味着这是一条绝对路径:见Class.getResource
  4. 我建议您在想要阅读文件时使用ClassLoader.html#getResourceAsStream
  5. 更新以回答评论:&#34;那么为什么Paths.get()不接受绝对路径?&#34;

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

    • 当您致电:getClass().getClassLoader().getResource("file.txt")时,会返回一个网址:file:/D:/Projects/myapp/build/resources/main/file.txt
      • 此网址由架构file:
      • 组成
      • 和有效(绝对网址)路径:/D:/Projects/myapp/build/resources/main/file.txt
    • 您尝试将此URL路径直接用作文件路径,这是错误的

    要将网址路径转换为有效的文件路径,您可以使用Paths.get(URI)方法,如下所示:

    URL fileUrl = getClass().getClassLoader().getResource("file.txt");
    String filePath = Paths.get(fileUrl.toURI());
    // now you have a valid file-path: D:/Projects/myapp/build/resources/main/file.txt
    

答案 1 :(得分:0)

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

为什么呢?当您离开IDE并将应用程序作为JAR或WAR交付时,资源将驻留在ZIP压缩文件中,并且没有文件&#34; file.txt&#34;您可以打开,只有JAR或WAR文件中的条目。

正如@TmTron所指出的,我还建议使用ClassLoader.getResourceAsStream()。这将适用于所有情况。