当我在 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 从远程存储库服务器加载,都无关紧要。