当应用程序部署为 JAR 时,为什么".."(两个句点)不能向上移动一个目录?



当我在 IDE 中运行应用程序时,使用..(两个句点)可以轻松访问父目录(相对于当前目录)。

下面是一个快速示例:

包结构

src
└───main
├───java
│   │   Main.java
│   │
│   └───controllers
│           Controller.java
│           InnerController.java
│
└───resources
└───fxml
inner-layout.fxml
layout.fxml

Controller里面,我试着说,"上一层,然后去找fxml/inner-layout.fxml"。

URL relativeResource = Controller.class.getResource("../fxml/inner-layout.fxml");
// Returns: "file:/C:/Users/BradTurek/IdeaProjects/Parent%20Directory%20Jar%20MCVE/build/resources/main/fxml/inner-layout.fxml"

这适用于文件系统。

但是,当我将应用程序部署为可执行.jar文件时,..不再被解释为"上一个目录"。我检查了:我仍然可以访问.jar中的资源 - 除非我使用包含..的路径。

似乎..在处理.jar内部的路径时不起作用。

这是上述示例的完整 MCVE,您可以自己下载并运行。

这个问题的答案在互联网上并不容易找到——尽管它可能就在那里。我希望我已经足够清楚地提出了这个问题,以便其他人很容易找到答案。

为什么会这样?

首先,可以说,该方法Class.getResource(String)没有指定对在路径中处理".."的任何支持。因此,您的问题的答案可以在这里以以下文字结束:">因为规范没有定义这种行为"。

当从 IDE 内部启动应用程序时,它之所以有效,是因为在这种情况下,本地文件系统工具用于访问资源。这些能够解决您路径中的".."。

但是 JAR 文件本身并不是一个文件系统 - 它只是一个压缩容器,以未定义的顺序保存所有.class文件和其他资源(请参阅 JAR 文件规范 - Oracle)。虽然它符合ZIP文件标准,其末尾包含一个目录列表,称为"中央目录"(参见ZIP(文件格式)-维基百科),但必须先使用此列表来构建树状的可导航路径结构,然后才能用于解析路径。我认为由于性能和内存消耗的原因,这不是通过类加载器加载类和其他资源时完成的。

但在您的情况下,实际上根本没有理由使用相对路径,因此依赖于路径解析。相反,您可以使用绝对路径。这听起来更糟,因为这种绝对路径在文件系统的意义上并不是真正的绝对路径,而只是相对于你的类路径根的绝对路径

所以这应该有效:

URL resource = Controller.class.getResource("/fxml/inner-layout.fxml");

无论资源是从文件系统、JAR 文件还是通过 HTTP 从远程存储库服务器加载,都无关紧要。

最新更新