我想在我的应用程序中随机显示 .gif。 我宁愿让我的代码“自我意识”它的内容。 这就是为什么不手动添加文件名 [如 List blabla .add("/example.gif")]
这在 IDE (intellij) 中工作得很好,但在 .jar 存档中停止。 我在处理资源时总是遇到类似的问题,但仍然无法克服这个问题。
这是我的类,旨在列出我的资源目录中包含的所有 .gif 文件:
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class ResourceHandler {
private static final String RESOURCE_PATH = "resources";
private static final List<String> GIF_NAMES_LIST = new ArrayList<>();
public ResourceHandler() {
File resourceDir = new File(RESOURCE_PATH);
File[] files = resourceDir.listFiles();
if (files != null) {
for (File file : files) {
GIF_NAMES_LIST.add(file.getName());
}
}
}
List<String> getGifNamesList() {
return GIF_NAMES_LIST;
}
}
我接下来在主程序中要做的事情:
String gifName = GIF_NAMES_LIST.get(RANDOM.nextInt(GIF_NAMES_LIST.size()));
我得到了什么: 线程“main”中的异常 java.lang.IllegalArgumentException:绑定必须为正 在 java.base/java.util.Random.nextInt(Random.java:322) 在 Main.main(Main.java:28)
我知道它不从资源中读取,因此长度为0。 那么我该如何修改我的
ResourceHandler
类呢?
对于这个常见问题似乎有很多误导性的答案,并且对于什么有效的方法有很多误解。
简短回答:不可能列出应用程序资源,除非在命名模块中使用 ModuleReader。安全、通用的解决方案是包含一个包含所有资源路径的文本文件。这是您的应用程序,因此您在构建时知道其中的内容。
您的课程可能不在目录中。它们可能位于 .jar 文件或应用程序映像中。 File 类仅适用于目录条目。
.jar 文件是一个存档文件,而不是目录。 .jar 文件中的条目不是文件;而是文件。它们只是存档的一部分,是嵌入在 .jar 文件中的压缩数据。它们无法通过 File 类列出或读取。
应用程序映像是组合应用程序模块的单个文件。其格式未记录。尝试了解该格式并不安全,因为它将来可能会更改,恕不另行通知。无法使用 File 类列出或读取图像中的条目。
一些解决方案建议使用 JarFile、JarInputStream 或 zip 文件系统 扫描 .jar 文件。这不安全有两个原因:
使用 getClass().getProtectionDomain().getCodeSource().getLocation() 查找应用程序 .jar 文件最终会失败,因为:
不保证应用程序位于 .jar 文件中。标准 jlink 工具生成的应用程序映像通常不包含 .jar 文件。此外,一些 Web 应用程序容器使用既不是普通目录也不是 .jar 文件的方案来部署应用程序。
这是您的应用程序。你已经知道里面有什么了。因此,创建一个纯文本文件,列出每个资源的路径。在运行时,您可以轻松读取该资源:
Collection<String> resourcePaths;
try (BufferedReader listing =
new BufferedReader(
new InputStreamReader(
MyApplication.class.getResourceAsStream(
"data-file-list.txt"),
StandardCharsets.UTF_8));
Stream<String> lines = listing.lines()) {
resourcePaths = lines.toList();
}
如果精通某些构建工具,甚至可以在构建时(而不是运行时)自动生成此列表文件。
有一种方法可以安全地列出资源,但只有当您的应用程序位于命名模块中时它才有效。您可以使用 ModuleReader.list():
Collection<String> resourcePaths;
String imagesPath = "com/example/myapp/images/";
Module m = MyApplication.class.getModule();
String moduleName = m.getName();
ResolvedModule resolved =
m.getLayer().configuration().findModule(moduleName).get();
try (ModuleReader reader = resolved.reference().open();
Stream<String> resources = reader.list()) {
resourcePaths =
resources.filter(r -> r.startsWith(imagesPath)).toList();
}