Eva*_*van 8 java nio java-module java-11
当我们通过JLINK创建Java运行时需要的所有Java类/资源,并把它们变成JRT映像文件:lib/modules。
这是我使用的基本 Maven 项目资源结构:
src
main
resources
dict
xkcd_en
Run Code Online (Sandbox Code Playgroud)
我只是想阅读xkcd_en文本文件。如果我们查看 JRT 文件,它是:
>> jimage list /path/to/lib/modules
...
Module: main
dict/xkcd_en
...
Run Code Online (Sandbox Code Playgroud)
此外,我已明确在 中打开它module-info,以防万一:
module main {
opens dict;
// ..rest code omitted
}
Run Code Online (Sandbox Code Playgroud)
我可以读取文件的唯一方法是将其作为输入流获取:
作品:
public static InputStream getResourceAsStream(String resource) {
return FileUtils.class.getResourceAsStream(resource);
}
System.out.println(new BufferedReader(
new InputStreamReader(getResourceAsStream("/dict/xkcd_en")))
.lines().collect(Collectors.joining("\n"))
);
Run Code Online (Sandbox Code Playgroud)
不工作:
但是,如果我试图获取文件 URI 并通过 Java NIO API 读取它,则它不起作用:
public static URL getResourceOrThrow(String resource) {
URL url = FileUtils.class.getResource(resource);
Objects.requireNonNull(url);
return url;
}
Run Code Online (Sandbox Code Playgroud)
1 - Java NIO 找不到文件。但它确实存在,否则getResource()返回null。
System.out.println(Paths.get(getResourceOrThrow("/dict/xkcd_en").toURI()));
// /main/dict/xkcd_en
Files.readAllLines(Paths.get(getResourceOrThrow("/dict/xkcd_en").toURI()));
Caused by: java.nio.file.NoSuchFileException: /main/dict/xkcd_en
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.newInputStream(JrtFileSystem.java:342)
at java.base/jdk.internal.jrtfs.JrtPath.newInputStream(JrtPath.java:631)
at java.base/jdk.internal.jrtfs.JrtFileSystemProvider.newInputStream(JrtFileSystemProvider.java:322)
Run Code Online (Sandbox Code Playgroud)
2 - 如果您将FileSystem直接使用,则相同:
FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
System.out.println(fs.getPath("main/dict/xkcd_en"));
// main/dict/xkcd_en
Files.readAllLines(fs.getPath("main/dict/xkcd_en")));
Caused by: java.nio.file.NoSuchFileException: /main/dict/xkcd_en
at java.base/jdk.internal.jrtfs.JrtFileSystem.checkNode(JrtFileSystem.java:494)
Run Code Online (Sandbox Code Playgroud)
3 - Java NIO 甚至不知道什么是jrt:/方案。
Files.readAllLines(Paths.get(getResourceOrThrow("/dict/xkcd_en").toExternalForm()));
Caused by: java.nio.file.InvalidPathException: Illegal char <:> at index 3: jrt:/main/dict/xkcd_en
at java.base/sun.nio.fs.WindowsPathParser.normalize(WindowsPathParser.java:182)
at java.base/sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:153)
at java.base/sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:77)
at java.base/sun.nio.fs.WindowsPath.parse(WindowsPath.java:92)
at java.base/sun.nio.fs.WindowsFileSystem.getPath(WindowsFileSystem.java:229)
at java.base/java.nio.file.Path.of(Path.java:147)
at java.base/java.nio.file.Paths.get(Paths.java:69)
Run Code Online (Sandbox Code Playgroud)
这是JRT FS的规格。
jrt URL 是分层 URI,符合 RFC 3986,语法为
jrt:/[$MODULE[/$PATH]]
其中 $MODULE 是可选的模块名称,$PATH(如果存在)是该模块中特定类或资源文件的路径。jrt URL 的含义取决于其结构:
- jrt:/$MODULE/$PATH 是指给定 $MODULE 中名为 $PATH 的特定类或资源文件。
- jrt:/$MODULE 是指模块 $MODULE 中的所有类和资源文件。
- jrt:/ 指的是存储在当前运行时映像中的整个类和资源文件集合。
所以获得的路径对我来说看起来不错。我哪里错了?
您引用的 JEP 部分专门处理 URL。如果您进一步阅读,您会发现它讨论 JRT 文件系统的地方:
URL 方案的内置 NIO
FileSystem提供程序jrt确保开发工具可以通过加载FileSystemURL 命名的来枚举和读取运行时映像中的类和资源文件jrt:/,如下所示:Run Code Online (Sandbox Code Playgroud)FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); byte[] jlo = Files.readAllBytes(fs.getPath("modules", "java.base", "java/lang/Object.class"));
modules此文件系统中的顶级目录[强调已添加]为映像中的每个模块包含一个子目录。顶级packages目录 [强调已添加]包含映像中每个包的一个子目录,该子目录包含一个符号链接,指向定义该包的模块的子目录。
如您所见,JRT 文件系统在根目录下有两个目录:modules和packages. 这些是作为JDK-8066492 的一部分添加的,该问题描述了它们的用途。所以问题不在于 NIO API 无法读取 JRT 映像中的资源。问题在于:
/main/dict/xkcd_en
Run Code Online (Sandbox Code Playgroud)
真的不存在。该资源实际上位于:
/modules/main/dict/xkcd_en
Run Code Online (Sandbox Code Playgroud)
JRT URL 采用以下三种形式之一(所有这些都在您在问题中引用的 JEP 部分中提到):
jrt:/$MODULE/$PATHjrt:/$MODULEjrt:/第一种形式用于访问JRT镜像中的特定资源以及我们关心的资源。如您所见,该 URL 不包括上面提到的顶级目录。您可以将 URL 视为始终相对于modules目录。
这就是说,作为指出通过@Alan贝特曼,你所遇到的错误。当您有一个 JRT URL 并尝试将其转换为 a 时,Path您应该得到一个Path指向现有文件的 。问题是这种转换没有考虑modules目录。
此错误已在 Java 13 中由JDK-8224946 修复。
| 归档时间: |
|
| 查看次数: |
1492 次 |
| 最近记录: |