问题列出“resources”目录中的文件名称。 (在 JAR/EXE 应用程序中)

问题描述 投票:0回答:1

我想在我的应用程序中随机显示 .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
类呢?

java jar io resources executable-jar
1个回答
0
投票

对于这个常见问题似乎有很多误导性的答案,并且对于什么有效的方法有很多误解。

简短回答:不可能列出应用程序资源,除非在命名模块中使用 ModuleReader。安全、通用的解决方案是包含一个包含所有资源路径的文本文件。这是您的应用程序,因此您在构建时知道其中的内容。

1.您不能使用 File 类。

您的课程可能不在目录中。它们可能位于 .jar 文件或应用程序映像中。 File 类仅适用于目录条目。

.jar 文件是一个存档文件,而不是目录。 .jar 文件中的条目不是文件;而是文件。它们只是存档的一部分,是嵌入在 .jar 文件中的压缩数据。它们无法通过 File 类列出或读取。

应用程序映像是组合应用程序模块的单个文件。其格式未记录。尝试了解该格式并不安全,因为它将来可能会更改,恕不另行通知。无法使用 File 类列出或读取图像中的条目。

2.您无法扫描 .jar 文件。

一些解决方案建议使用 JarFile、JarInputStream 或 zip 文件系统 扫描 .jar 文件。这不安全有两个原因:

  • 使用 getClass().getProtectionDomain().getCodeSource().getLocation() 查找应用程序 .jar 文件最终会失败,因为:

  • 不保证应用程序位于 .jar 文件中。标准 jlink 工具生成的应用程序映像通常不包含 .jar 文件。此外,一些 Web 应用程序容器使用既不是普通目录也不是 .jar 文件的方案来部署应用程序。

3.纯文本列表文件是最好的方法。

这是您的应用程序。你已经知道里面有什么了。因此,创建一个纯文本文件,列出每个资源的路径。在运行时,您可以轻松读取该资源:

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();
}

如果精通某些构建工具,甚至可以在构建时(而不是运行时)自动生成此列表文件。

4.您可以列出 Java 模块中的资源。

有一种方法可以安全地列出资源,但只有当您的应用程序位于命名模块中时它才有效。您可以使用 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();
}
© www.soinside.com 2019 - 2024. All rights reserved.