【问题标题】:How to load a folder from a .jar?如何从 .jar 加载文件夹?
【发布时间】:2011-09-08 23:34:02
【问题描述】:

好的。所以我有一个非常简单的问题:我希望能够从正在运行的 .jar 文件中加载资源(整个文件夹),但我无法让它工作。这是我尝试过的(如果类名是“myClass”并且文件夹被称为“myFolder”),但它总是抛出 NullPointerException:

URL folderURL = myClass.class.getClassLoader().getResource("myFolder/");
String folderPath = folderURL.getPath();
File myFolder = new File(folderPath);

在我创建“myFolder”之前总是抛出 NullPointerException。

更多信息:我必须从静态上下文访问文件夹。访问该文件夹的类与文件夹本身不在同一目录中。(该文件夹在 jar 内的根目录中,该类是几个子包。)

有人能解决我的问题吗?抱歉,如果我使用了错误的术语:P,但您可以做的任何事情都非常感谢。

【问题讨论】:

  • @userNNNN:“我有一个非常简单的问题:”“生命的意义是什么?”是一个简单的问题。这是一个棘手的答案。顺便说一句 - 既然您显然将文件放入 Jar 中,为什么不将它们的列表包含在具有集合名称的单个文件中。问题解决了!

标签: java url resources directory


【解决方案1】:

这是不可能的。您正在尝试从 JAR 中的资源创建 File 对象。这不会发生。加载资源的最佳方法是将您的包文件夹设为资源文件夹,然后在其中创建一个 Resources.jar 或其他内容,将您的资源转储到同一目录中,然后在您的其他 Java 类文件中使用Resources.class.getResourceAsStream(resFileName)。

如果您需要“暴力破解”getResource(..) 给出的 URL 所指向的 JAR 目录中的子文件,请使用以下命令(尽管这有点小技巧!)。它也适用于普通文件系统:

  /**
   * List directory contents for a resource folder. Not recursive.
   * This is basically a brute-force implementation.
   * Works for regular files and also JARs.
   * 
   * @author Greg Briggs
   * @param clazz Any java class that lives in the same place as the resources you want.
   * @param path Should end with "/", but not start with one.
   * @return Just the name of each member item, not the full paths.
   * @throws URISyntaxException 
   * @throws IOException 
   */
  String[] getResourceListing(Class clazz, String path) throws URISyntaxException, IOException {
      URL dirURL = clazz.getClassLoader().getResource(path);
      if (dirURL != null && dirURL.getProtocol().equals("file")) {
        /* A file path: easy enough */
        return new File(dirURL.toURI()).list();
      } 

      if (dirURL == null) {
        /* 
         * In case of a jar file, we can't actually find a directory.
         * Have to assume the same jar as clazz.
         */
        String me = clazz.getName().replace(".", "/")+".class";
        dirURL = clazz.getClassLoader().getResource(me);
      }

      if (dirURL.getProtocol().equals("jar")) {
        /* A JAR path */
        String jarPath = dirURL.getPath().substring(5, dirURL.getPath().indexOf("!")); //strip out only the JAR file
        JarFile jar = new JarFile(URLDecoder.decode(jarPath, "UTF-8"));
        Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
        Set<String> result = new HashSet<String>(); //avoid duplicates in case it is a subdirectory
        while(entries.hasMoreElements()) {
          String name = entries.nextElement().getName();
          if (name.startsWith(path)) { //filter according to the path
            String entry = name.substring(path.length());
            int checkSubdir = entry.indexOf("/");
            if (checkSubdir >= 0) {
              // if it is a subdirectory, we just return the directory name
              entry = entry.substring(0, checkSubdir);
            }
            result.add(entry);
          }
        }
        return result.toArray(new String[result.size()]);
      } 

      throw new UnsupportedOperationException("Cannot list files for URL "+dirURL);
  }

然后您可以修改getResource(..) 给出的URL 并将文件附加到末尾,并将这些URL 传递给getResourceAsStream(..),准备加载。如果你不明白这一点,你需要阅读类加载。

【讨论】:

  • @param clazz Any java class that lives in the same place as the resources you want. "in the same place" 与同一个 JAR 中一样,还是...?
  • 请记住getClass().getClassLoader().getResource(...) 和getClass().getResource(...) 之间存在差异。 getResourceAsStream(...) 也是如此。这看起来像使用 jar 的根作为根的“无基础”版本,本质上。试试看——在你的 JAR 根目录下放一个资源文件夹,看看它是否可以列出其中的文件。
  • 感谢您(和 Greg Briggs),Java 中的某些文件操作可以如此复杂,这真是令人难以置信。当然,现在我看到了代码,这很有意义,但在那之前……哦,伙计。
  • 请注意,您可以使用 clazz.getProtectionDomain().getCodeSource().getLocation() 获取类的 jar 位置。
【解决方案2】:

很简单:

getClass().getResourceAsStream("/resources/images/myImage.png")

将返回一个可以像这样使用的输入流:

Image myImage = ImageIO.read(getClass().getResourceAsStream("/resources/images/myImage.png"));

然后,您可以随心所欲地使用您的图片。如果您使用输入流来读取文本文件,或者您正在做的任何其他事情,这也同样有效。

编辑: 上面的路径是相对于 .jar 的根目录的。

【讨论】:

  • 当你说getClass时,你指的是getClass()吗?
  • 如果访问文件夹的类在 myJar.myPackage.myFirstSubpackage.mySecondSubpackage 中,而文件夹只是在 myJar.myFolder 中怎么办?
  • 好的,谢谢。所以我可以这样做:File myFolder = myClass.class.getResourceAsStream("/myFolder/") 对吗?等等,那行不通:P
  • 那里没有你可以从 JAR 中获取 File 对象。没门。 API 不允许这样做。把它从你的脑海里拿出来:)
  • 哈哈。所以我必须做更多的工作xD。嗯……就这么多。感谢您尝试帮助我:)
【解决方案3】:

我想我正在做某事。在 Eclipse 中,创建一个名为“resources”的新源文件夹,并在该文件夹中创建一个名为“myFolder”的包。要获得“myFolder”的路径,您只需说:

Path path = Paths.get(Main.class.getResource("/myFolder").toURI()); // or the class name instead of Main

【讨论】:

    【解决方案4】:

    到目前为止(2017 年 12 月),这是我发现的唯一一个在 IDE 内外都 工作的解决方案(使用 PathMatchingResourcePatternResolver):https://stackoverflow.com/a/47904173/6792588 p>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-07-30
      • 2012-06-16
      • 1970-01-01
      • 1970-01-01
      • 2018-06-03
      • 2023-04-11
      • 2011-04-24
      相关资源
      最近更新 更多