当应用程序作为 JAR 部署时,为什么“..”(两个句点)不能上升到一个目录?

Why doesn't ".." (two periods) work to go up one directory when the application is deployed as a JAR?

当我 运行 在 IDE 中的应用程序时,accessing the parent directory(相对于当前目录)可以通过使用 ..(两个句点)轻松完成。

这是一个简单的例子:

包结构

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

Controller 里面,我试着说,"Go up one level and then go find 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 文件时,.. 不再被解释为 "go up one directory"。我检查过:我可以 仍然 访问 .jar 中的资源——除非我使用包含 ...

的路径

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

这里是 a full MCVE of the above example,您可以下载并 运行 自己。

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

为什么会这样?

首先要说的是,方法Class.getResource(String)没有指定任何支持处理路径中的“..”。所以你的问题的答案可以在这里结束:"Because the spec does not define this behaviour".

从 IDE 内部启动应用程序时它起作用的原因是,在这种情况下,本地文件系统设施用于访问资源。这些能够解决您路径中的“..”。

但 JAR 文件本身并不是一个文件系统 - 它只是一个压缩容器,以 non-defined 顺序保存所有 .class 文件和其他资源(参见 JAR file specification - Oracle). Although it conforms to the ZIP file standard, which contains a directory listing at its end, called the 'central directory' (see ZIP (file format) - Wikipedia),必须首先使用此列表来构建 tree-like 可导航路径结构,然后才能将其用于解析路径。我假设由于性能和内存消耗的原因,这不是通过 class 加载程序加载 classes 和其他资源完成的。

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

所以这应该有效:

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

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