当应用程序作为 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 从远程存储库服务器加载,都没有关系。
当我 运行 在 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 从远程存储库服务器加载,都没有关系。