3

I need to take a look at the names of files inside a specific package. Currently, I'm doing the following:

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

// Work with the files inside the directory

This actually works just fine in Eclipse, since it doesn't package my application by default. When I run it from a jar file, however, I get a NullPointerException on packageUrl.

So, how do I obtain a list of the contents of a package that's inside a jar? My research suggested using getResourceAsStream, but I'm not quite sure how to explore a directory with an InputStream, if that's even possible.

Matheus Moreira
  • 17,106
  • 3
  • 68
  • 107

2 Answers2

5

You could get path to the jar file and open it with ZipInputStream list all the files inside that jar.

To know the path of the running jar, try using:

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

See also: How do I list the files inside a JAR file?

update

I've compiled an ran your solution and works perfect:

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
Community
  • 1
  • 1
OscarRyz
  • 196,001
  • 113
  • 385
  • 569
  • I tried that, but `getNextEntry()` seems to always return `null`. `getLocation()` returns `rsrc:./`. Any idea on what could be the problem? I'm trying to read files from my application's own jar, by the way... I think I should have mentioned that. – Matheus Moreira Feb 21 '11 at 18:59
  • Do you have some sample we can see? I've used the previously mentioned code to load all the images inside my jar and worked well: http://meta.stackexchange.com/questions/20420/countdown-app-for-devdays/21848#21848 – OscarRyz Feb 21 '11 at 19:40
  • Looking at it. In the mean time, did you notice this? http://stackoverflow.com/questions/1429172/list-files-inside-a-jar/1435649#1435649 – OscarRyz Feb 22 '11 at 00:20
  • Yeah. I based my implementation on that answer, but did it differently. Did I miss anything? – Matheus Moreira Feb 22 '11 at 00:27
  • That's very strange. What does your call to `getLocation()` return? Does that method return a location relative to the calling class? The entries I'm looking for are on a different package tree, so that might be the problem. – Matheus Moreira Feb 22 '11 at 00:43
  • Nope, absolute path to my jar: `file:/C:/java/injar/i18n.jar` – OscarRyz Feb 22 '11 at 15:22
  • [Asked a question about this specific problem.](http://stackoverflow.com/q/5206619/512904) Your solution works fine, I'm accepting your answer. – Matheus Moreira Mar 08 '11 at 01:24
3

You can use a JarInputStream to read the contents of a jar file. You'll iterate over the JarEntry objects returned by getNextJarEntry() which have a getName(). If you don't care about any of the jar-specific metadata, such a code-signers or additional Manifest entries, you can stick with the ZipInputStream superclass.

BobV
  • 4,143
  • 1
  • 18
  • 27