如何访问jar文件中文件夹的内容?

3

我需要查看特定包内文件的名称。目前,我正在执行以下操作:

ClassLoader loader = Thread.currentThread().getContextClassLoader();
URL packageUrl = loader.getResource(getPackage().replace('.', '/'));
File packageDir = new File(packageUrl.getFile());

// Work with the files inside the directory

在Eclipse中,这个方法非常有效,因为它默认不会将我的应用程序打包。但是,当我从一个jar文件运行它时,我会在packageUrl上得到NullPointerException

那么,如何获取一个位于jar包内部的包内容列表呢?我的研究表明可以使用getResourceAsStream,但我不太确定如何使用InputStream探索目录,如果有可能的话。

2个回答

5

您可以获取jar文件的路径,然后使用ZipInputStream打开它并列出其中所有的文件。

要知道正在运行的jar文件的路径,请尝试使用以下方法:

InputStream in = MyClass
                .class
                .getProtectionDomain()
                .getCodeSource()
                .getLocation()
                .openStream();

参见:如何列出JAR文件中的文件?

更新

我已经编译并运行了您的解决方案,完美地工作:

C:\java\injar>dir
 El volumen de la unidad C no tiene etiqueta.
 El número de serie del volumen es: 22A8-203B

 Directorio de C:\java\injar

21/02/2011  06:23 p.m.    <DIR>          .
21/02/2011  06:23 p.m.    <DIR>          ..
21/02/2011  06:23 p.m.             1,752 i18n.jar
21/02/2011  06:23 p.m.    <DIR>          src
21/02/2011  06:21 p.m.    <DIR>          x

C:\java\injar>jar -tf i18n.jar
META-INF/
META-INF/MANIFEST.MF
I18n.class
x/
x/y/
x/y/z/
x/y/z/hola.txt

C:\java\injar>type src\I18n.java
import java.util.*;
import java.net.*;
import java.util.jar.*;
class I18n {
    public static void main( String ... args ) {
        getLocaleListFromJar();
    }
    private static List<Locale> getLocaleListFromJar() {
        List<Locale> locales = new ArrayList<Locale>();
        try {
            URL packageUrl = I18n.class.getProtectionDomain().getCodeSource().getLocation();
            JarInputStream jar = new JarInputStream(packageUrl.openStream());
            while (true) {
                JarEntry entry = jar.getNextJarEntry();
                if (entry == null) {
                    System.out.println( "entry was null ");
                    break;
                }
                String name = entry.getName();
                System.out.println( "found : " +name );
                /*if (resourceBundlePattern.matcher(name).matches()) {
                    addLocaleFromResourceBundle(name, locales);
                }*/
           }
        } catch (Exception e) {
            System.err.println(e);
            return null;
            //return getLocaleListFromFile(); // File based implementation in case resources are not in jar
        }
        return locales;
    }
}


C:\java\injar>java -jar i18n.jar
found : I18n.class
found : x/
found : x/y/
found : x/y/z/
found : x/y/z/hola.txt
entry was null

我尝试过了,但是 getNextEntry() 似乎总是返回 nullgetLocation() 返回 rsrc:./。你有什么想法吗?顺便说一下,我正在尝试从我的应用程序自己的 jar 文件中读取文件...我想我应该提到这一点。 - Matheus Moreira
你有一些我们可以看到的样例吗?我已经使用之前提到的代码来加载我的jar中的所有图像,并且效果很好:http://meta.stackexchange.com/questions/20420/countdown-app-for-devdays/21848#21848 - OscarRyz
看一下。同时,你有注意到这个吗?https://dev59.com/CHM_5IYBdhLWcg3wUxZB#1435649 - OscarRyz
是的。我基于那个答案实现了我的代码,但是我做了一些不同的改动。我有遗漏什么吗? - Matheus Moreira
关于这个具体问题,我提出了一个问题。你的解决方案很好,我接受了你的答案。 - Matheus Moreira
显示剩余2条评论

3
你可以使用JarInputStream来读取jar文件的内容。你需要迭代通过getNextJarEntry()返回的JarEntry对象,这些对象有一个getName()方法。如果你不关心jar特定的元数据,例如代码签名或额外的清单条目,你可以使用ZipInputStream超类。

+1 对于 Jar 特定的类,我将来可能会需要它。 - Matheus Moreira

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接