java 如何从 .jar 加载文件夹?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6247144/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 15:00:36  来源:igfitidea点击:

How to load a folder from a .jar?

javaurlresourcesdirectory

提问by Chris Dennett

OK. So I have a pretty simple question: I want to be able to load a resource (a whole folder) from inside a running .jar file, but I have not been able to get it to work. This is what I have tried (if the class name were "myClass" and the folder being called "myFolder"), but it always throws a NullPointerException:

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

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

The NullPointerException is always thrown before I create "myFolder".

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

Some more info: I have to access the folder from static context. The class that is accessing the folder is NOT in the same directory as the folder itself is in. (The folder is in the root directory inside the jar, the class is a couple subpackages down.)

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

Does anyone have a solution to my problem? Sorry if I used wrong terminology :P, but anything you can do to help is appreciated.

有没有人能解决我的问题?抱歉,如果我使用了错误的术语:P,但是您可以提供任何帮助,我们将不胜感激。

回答by Chris Dennett

There's no way this will work. You're trying to create a File object from a resource inside a JAR. That isn't going to happen. The best method to load resources is to make one your package folders a resource folder, then make a Resources.jar in it or something, dump your resources in the same dir, and then use Resources.class.getResourceAsStream(resFileName)in your other Java class files.

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

If you need to 'brute force' the subfiles in the JAR directory pointed to by the URL given by getResource(..), use the following (although it's a bit of a hack!). It will work for a normal filesystem too:

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

  /**
   * 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);
  }

You can then modify the URL given by getResource(..)and append the file on the end, and pass these URLs into getResourceAsStream(..), ready for loading. If you didn't understand this, you need to read up on classloading.

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

回答by kryo

It's pretty simple:

这很简单:

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

Would return an input stream which can be used like so:

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

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

And from there, use your Image how you like. This also works just as well if you're using the input stream to read a text file, or for pretty much whatever else you're doing.

从那里开始,按照您的喜好使用您的图像。如果您使用输入流来读取文本文件,或者几乎您正在做的任何其他事情,这也同样适用。

Edit: The path above is relative to the .jar's root.

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

回答by Valdrinium

I think I am on to something. In Eclipse, make a new source folder named "resources" and in that folder, create a package named "myFolder". To have a Path to "myFolder", you just have to say:

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

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

回答by Naor Bar

Up until now (December 2017), this is the only solution I found which works bothinside and outside the IDE (Using PathMatchingResourcePatternResolver): https://stackoverflow.com/a/47904173/6792588

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