我无法从使用Java JLink工具创建的应用程序映像中读取外部文件

问题描述

在应用程序运行时,无法从使用JLink工具(mvn javaf:jlink)创建的应用程序映像中读取外部文件。外部文件位于 resources 文件夹中。这是我得到的错误:

ERROR ExecutorOfFiles Script failed to read or load: SampleScript.jsh
java.nio.file.NoSuchFileException: /com.luisosv/com/luisosv/SampleScript.jsh
        at java.base/jdk.internal.jrtfs.JrtFileSystem.checkNode(JrtFileSystem.java:494)
        at java.base/jdk.internal.jrtfs.JrtFileSystem.getFileContent(JrtFileSystem.java:253)
        at java.base/jdk.internal.jrtfs.JrtFileSystem.newByteChannel(JrtFileSystem.java:351)
        at java.base/jdk.internal.jrtfs.JrtPath.newByteChannel(JrtPath.java:696)
        at java.base/jdk.internal.jrtfs.JrtFileSystemProvider.newByteChannel(JrtFileSystemProvider.java:302)
        at java.base/java.nio.file.Files.newByteChannel(Files.java:370)
        at java.base/java.nio.file.Files.newByteChannel(Files.java:421)
        at java.base/java.nio.file.Files.readAllBytes(Files.java:3205)
        at com.luisosv@1.0-SNAPSHOT/com.luisosv.ExecutorOfFiles.loadSnippetsFromFile(ExecutorOfFiles.java:55)

我正在使用以下内容读取外部文件:

String sourceCode = new String(Files.readAllBytes(
                Paths.get(
                        this.getClass().getResource(scriptFileName).toURI())));

但是,从命令行使用该应用程序可以正常运行mvn javafx:run

我已经阅读到应用程序映像一旦创建,就无法更新或打补丁。对于任何更改,都需要从https://www.studytrails.com/java/java-9/java-9-jlink/部署一个新的应用程序,我不知道这是原因还是其他原因。

谢谢。

解决方法

jrt文件系统的资源查找中存在一个错误,该错误会影响13之前的Java版本。

当我运行以下代码片段时:

Path p = Paths.get(Object.class.getResource("Object.class").toURI());
System.out.println(p);
System.out.println(Files.exists(p));

从9到12的所有JDK都会产生以下输出:

/java.base/java/lang/Object.class
false

从JDK 13开始,输出为

/modules/java.base/java/lang/Object.class
true

同样,Files.readAllBytes(Paths.get(Object.class.getResource("Object.class").toURI()))产生与问题中的异常类似的异常java.nio.file.NoSuchFileException: /java.base/java/lang/Object.class,显示了JDK 9至12的路径,该路径带有模块名称,但没有前面的/modules。 >

因此,只需切换到JDK 13或更高版本即可解决您的问题。


但是请注意,使用

byte[] b = Object.class.getResourceAsStream("Object.class").readAllBytes();

或更清洁

try(InputStream is = Object.class.getResourceAsStream("Object.class")) {
    byte[] b = is.readAllBytes();
}

适用于从9到14的所有版本。因此,我建议首先使用getResourceAsStream,而不要使用URLURIPath绕行。


也就是说,您不应使用String(byte[])构造函数。使用系统的默认字符编码,此构造函数的结果将取决于当前环境,而嵌入式资源的实际编码将永远不会改变。

使用,例如new String(b,StandardCharsets.UTF_8),或指定您的资源进行编码的任何方式。

,

如果文件打包在JAR文件中,则无法将资源作为文件加载。请改用getResourceAsStream(...)

new String(this.getClass().getResourceAsStream(scriptFileName).readAllBytes());

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...