152 votes

Comment lister les fichiers dans un fichier JAR?

J'ai ce code qui lit tous les fichiers d'un répertoire.

    File textFolder = new File("text_directory");

    File [] texFiles = textFolder.listFiles( new FileFilter() {
           public boolean accept( File file ) {
               return file.getName().endsWith(".txt");
           }
    });

Il fonctionne très bien. Il remplit le tableau avec tous les fichiers qui se terminent par ".txt" du répertoire "text_directory".

Comment puis-je lire le contenu d'un répertoire dans un mode similaire au sein d'un fichier JAR?

Donc, ce que je veux vraiment faire est de, à la liste de toutes les images à l'intérieur de mon fichier JAR, afin que je puisse les charger avec:

ImageIO.read(this.getClass().getResource("CompanyLogo.png"));

(Que l'on travaille parce que le "CompanyLogo" est "codé en dur", mais le nombre d'images à l'intérieur du fichier JAR peut être de 10 à 200 de longueur variable.)

MODIFIER

Donc, je pense que mon principal problème pourrait être: Comment connaître le nom du fichier JAR où ma classe principale vies?

Certes, j'ai pu le lire à l'aide de java.util.Zip.

Ma Structure est comme ceci:

Ils sont comme:

my.jar!/Main.class
my.jar!/Aux.class
my.jar!/Other.class
my.jar!/images/image01.png
my.jar!/images/image02a.png
my.jar!/images/imwge034.png
my.jar!/images/imagAe01q.png
my.jar!/META-INF/manifest 

Maintenant je suis en mesure de charger par exemple "images/image01.png" aide:

    ImageIO.read(this.getClass().getResource("images/image01.png));

Mais seulement parce que je sais le nom du fichier, pour le reste, je dois charger dynamiquement.

111voto

erickson Points 127945
 CodeSource src = MyClass.class.getProtectionDomain().getCodeSource();
if (src != null) {
  URL jar = src.getLocation();
  ZipInputStream zip = new ZipInputStream(jar.openStream());
  while(true) {
    ZipEntry e = zip.getNextEntry();
    if (e == null)
      break;
    String name = e.getName():
    if (name.startsWith("path/to/your/dir/")) {
      /* Do something with this entry. */
      ...
    }
  }
} 
else {
  /* Fail... */
}
 

Notez que sous Java 7, vous pouvez créer un FileSystem partir du fichier JAR (zip), puis utiliser les mécanismes de recherche et filtrage du répertoire de NIO pour le parcourir. Cela faciliterait l'écriture de code qui gère les JAR et les répertoires "éclatés".

25voto

OscarRyz Points 82553

La réponse d' Erickson a parfaitement fonctionné:

Voici le code de travail.

 CodeSource src = MyClass.class.getProtectionDomain().getCodeSource();
List<String> list = new ArrayList<String>();

if( src != null ) {
    URL jar = src.getLocation();
    ZipInputStream zip = new ZipInputStream( jar.openStream());
    ZipEntry ze = null;

    while( ( ze = zip.getNextEntry() ) != null ) {
        String entryName = ze.getName();
        if( entryName.startsWith("images") &&  entryName.endsWith(".png") ) {
            list.add( entryName  );
        }
    }

 }
 webimages = list.toArray( new String[ list.size() ] );
 

Et je viens de modifier ma méthode de chargement à partir de ceci:

 File[] webimages = ... 
BufferedImage image = ImageIO.read(this.getClass().getResource(webimages[nextIndex].getName() ));
 

Pour ça:

 String  [] webimages = ...

BufferedImage image = ImageIO.read(this.getClass().getResource(webimages[nextIndex]));
 

9voto

Kevin Day Points 9446

Donc je suppose que mon principal problème, comment savoir le nom de la jarre où ma classe principale vies.

En supposant que votre projet est emballé dans un Bocal (pas forcément vrai!), vous pouvez utiliser le chargeur de classe.getResource() ou findResource() avec le nom de la classe suivi .classe) pour obtenir le pot qui contient une classe donnée. Vous aurez à analyser le pot de nom à partir de l'URL qui revient (pas difficile), je laisse comme exercice pour le lecteur :-)

Assurez-vous de tester pour le cas où la classe ne fait pas partie d'un bocal.

5voto

Ran Biron Points 3015

Voici une méthode que j'ai écrite pour "exécuter tous les JUnits sous un paquet". Vous devriez être capable de l'adapter à vos besoins.

 private static void findClassesInJar(List<String> classFiles, String path) throws IOException {
    final String[] parts = path.split("\\Q.jar\\\\E");
    if (parts.length == 2) {
        String jarFilename = parts[0] + ".jar";
        String relativePath = parts[1].replace(File.separatorChar, '/');
        JarFile jarFile = new JarFile(jarFilename);
        final Enumeration<JarEntry> entries = jarFile.entries();
        while (entries.hasMoreElements()) {
            final JarEntry entry = entries.nextElement();
            final String entryName = entry.getName();
            if (entryName.startsWith(relativePath)) {
                classFiles.add(entryName.replace('/', File.separatorChar));
            }
        }
    }
}
 

Edit: Ah, dans ce cas, vous voudrez peut-être aussi cet extrait (même cas d'utilisation :))

 private static File findClassesDir(Class<?> clazz) {
    try {
        String path = clazz.getProtectionDomain().getCodeSource().getLocation().getFile();
        final String codeSourcePath = URLDecoder.decode(path, "UTF-8");
        final String thisClassPath = new File(codeSourcePath, clazz.getPackage().getName().repalce('.', File.separatorChar));
    } catch (UnsupportedEncodingException e) {
        throw new AssertionError("impossible", e);
    }
}
 

3voto

berni Points 1247

Il y a quelque temps, j'ai créé une fonction qui obtient les classes de JAR:

 public static Class[] getClasses(String packageName) 
throws ClassNotFoundException{
    ArrayList<Class> classes = new ArrayList<Class> ();

    packageName = packageName.replaceAll("\\." , "/");
    File f = new File(jarName);
    if(f.exists()){
        try{
            JarInputStream jarFile = new JarInputStream(
                    new FileInputStream (jarName));
            JarEntry jarEntry;

            while(true) {
                jarEntry=jarFile.getNextJarEntry ();
                if(jarEntry == null){
                    break;
                }
                if((jarEntry.getName ().startsWith (packageName)) &&
                        (jarEntry.getName ().endsWith (".class")) ) {
                    classes.add(Class.forName(jarEntry.getName().
                            replaceAll("/", "\\.").
                            substring(0, jarEntry.getName().length() - 6)));
                }
            }
        }
        catch( Exception e){
            e.printStackTrace ();
        }
        Class[] classesA = new Class[classes.size()];
        classes.toArray(classesA);
        return classesA;
    }else
        return null;
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X