如何在可导出库中正确设置资源

How to correctly setup resources in a exportable library

在我创建的库中,我有以下行来检索我的资源:

private static final File fragment = new File(DefaultShader.class.getClassLoader().getResource("file.txt").getFile());

但是当我将此库导出到 JAR 并尝试在另一个应用程序中使用它时,当在内部读取同一行时,我收到 I/O 错误,因为它正在尝试访问 JAR。

java.io.FileNotFoundException: file:\C:\Users\me\test\libs\lib.jar!\file.txt

Nodejs 会通过提供 returns 脚本的运行时位置路径的方法使这更容易,显然 Java 中没有等效项或者只是找不到它。我怎样才能解决这个问题?

永远不要调用 URL 的 getFile 方法。它不是 return 有效的文件名。它只是 return 的路径部分 URL。

.jar 文件中嵌入的资源不是文件,您不能将其称为文件。

幸运的是,您不需要 File 对象。您可以直接使用 getResourceAsStream:

阅读
DefaultShader.class.getResourceAsStream("/file.txt")

显然,您不应将 InputStream 存储在 static final 字段中。但是您可以轻松地创建一个方法:

private static InputStream readFileData() {
    return DefaultShader.class.getResourceAsStream("/file.txt");
}

请注意,资源应该放在包中,就像 classes 一样。将资源放在 .jar 的根目录中就像将文件写入驱动器的根目录或用户的主目录:如果任何其他程序选择使用相同的文件名,至少可以说这两个程序的结果都会有问题.

同理,如果你的资源在你的.jar的根目录下,而另一个库恰好在自己的.jar的根目录下也存放了一个同名的资源,就会产生冲突,可能或者可能不是由 getResource* 方法加载的资源,具体取决于当前的 classpath 定义。 (此问题不适用于 Java 9+ 模块化程序,但将资源保存在包中仍然是个好主意。)

将资源与使用它的 class 放在同一个包中的做法被 Java SE 认为是一个很好的做法:getResourcegetResourceAsStream默认情况下,方法被设计为期望它与​​ class 在同一个包中。如果字符串参数不以斜杠开头,这些方法会假定它在同一个包中。

这会在与 DefaultShader class 相同的包中查找 file.txt:

DefaultShader.class.getResourceAsStream("file.txt")

而这将在 class 路径中的每个 .jar 的根目录中查找 file.txt:

DefaultShader.class.getResourceAsStream("/file.txt")