web-dev-qa-db-fra.com

Comment puis-je obtenir une ressource "Dossier" à l'intérieur de mon fichier jar?

J'ai un dossier/package de ressources à la racine de mon projet, je "ne" veux pas charger un certain fichier. Si je voulais charger un certain fichier, j'utiliserais class.getResourceAsStream et tout irait bien !! Ce que je veux réellement faire est de charger un "dossier" dans le dossier de ressources, de boucler sur les fichiers de ce dossier et d'obtenir un flux pour chaque fichier et de lire le contenu ... Supposons que les noms de fichiers ne sont pas déterminés avant l'exécution ... Que devrais-je faire? Existe-t-il un moyen d’obtenir une liste des fichiers d’un dossier dans votre fichier jar? Notez que le fichier JAR avec les ressources est le même fichier JAR à partir duquel le code est exécuté ...

Merci d'avance...

110
Mostafa Zeinali

Finalement, j'ai trouvé la solution:

final String path = "sample/folder";
final File jarFile = new File(getClass().getProtectionDomain().getCodeSource().getLocation().getPath());

if(jarFile.isFile()) {  // Run with JAR file
    final JarFile jar = new JarFile(jarFile);
    final Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
    while(entries.hasMoreElements()) {
        final String name = entries.nextElement().getName();
        if (name.startsWith(path + "/")) { //filter according to the path
            System.out.println(name);
        }
    }
    jar.close();
} else { // Run with IDE
    final URL url = Launcher.class.getResource("/" + path);
    if (url != null) {
        try {
            final File apps = new File(url.toURI());
            for (File app : apps.listFiles()) {
                System.out.println(app);
            }
        } catch (URISyntaxException ex) {
            // never happens
        }
    }
}

Le second bloc ne fonctionne que lorsque vous exécutez l'application sur IDE (pas avec le fichier jar). Vous pouvez le supprimer si vous n'aimez pas cela.

102
user1079877

Essayez ce qui suit.
Définir le chemin de la ressource "<PathRelativeToThisClassFile>/<ResourceDirectory>" E.g. si votre chemin de classe est com.abc.package.MyClass et que vos fichiers de ressources se trouvent dans src/com/abc/package/resources /:

URL url = MyClass.class.getResource("resources/");
if (url == null) {
     // error - missing folder
} else {
    File dir = new File(url.toURI());
    for (File nextFile : dir.listFiles()) {
        // Do something with nextFile
    }
}

Vous pouvez aussi utiliser 

URL url = MyClass.class.getResource("/com/abc/package/resources/");
15
Glen Best

Je sais que cela fait plusieurs années. Mais juste pour les autres personnes rencontrées dans ce sujet… .. Ce que vous pourriez faire est d'utiliser la méthode getResourceAsStream() avec le chemin du répertoire et le flux d'entrée aura tous les noms de fichiers de ce répertoire. Après cela, vous pouvez concatter le chemin du répertoire avec chaque nom de fichier et appeler getResourceAsStream pour chaque fichier d'une boucle.

6
Cheng Lin

J'avais le même problème lorsque j'essayais de charger des configurations hadoop à partir de ressources contenues dans le fichier jar ... à la fois sur le IDE et sur le fichier jar (version publiée).

J'ai trouvé que Java.nio.file.DirectoryStream fonctionnait de manière optimale pour parcourir le contenu du répertoire sur le système de fichiers local et le fichier jar.

String fooFolder = "/foo/folder";
....

ClassLoader classLoader = foofClass.class.getClassLoader();
try {
    uri = classLoader.getResource(fooFolder).toURI();
} catch (URISyntaxException e) {
    throw new FooException(e.getMessage());
} catch (NullPointerException e){
    throw new FooException(e.getMessage());
}

if(uri == null){
    throw new FooException("something is wrong directory or files missing");
}

/** i want to know if i am inside the jar or working on the IDE*/
if(uri.getScheme().contains("jar")){
    /** jar case */
    try{
        URL jar = FooClass.class.getProtectionDomain().getCodeSource().getLocation();
        //jar.toString() begins with file:
        //i want to trim it out...
        Path jarFile = Paths.get(jar.toString().substring("file:".length()));
        FileSystem fs = FileSystems.newFileSystem(jarFile, null);
        DirectoryStream<Path> directoryStream = Files.newDirectoryStream(fs.getPath(fooFolder));
        for(Path p: directoryStream){
            InputStream is = FooClass.class.getResourceAsStream(p.toString()) ;
        performFooOverInputStream(is);
        /** your logic here **/
            }
    }catch(IOException e) {
        throw new FooException(e.getMessage());     
    }
}
else{
    /** IDE case */
    Path path = Paths.get(uri);
    try {
        DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path);
        for(Path p : directoryStream){
            InputStream is = new FileInputStream(p.toFile());
            performFooOverInputStream(is);
        }
    } catch (IOException _e) {
        throw new FooException(_e.getMessage());
    }
}
5
SQL.injection

Le code suivant renvoie le "dossier" souhaité en tant que chemin, qu'il soit ou non à l'intérieur d'un fichier .jar. 

  private Path getFolderPath() throws URISyntaxException, IOException {
    URI uri = getClass().getClassLoader().getResource("folder").toURI();
    if ("jar".equals(uri.getScheme())) {
      FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap(), null);
      return fileSystem.getPath("path/to/folder/inside/jar");
    } else {
      return Paths.get(uri);
    }
  }

Nécessite Java 7+.

2
hummingV

Une autre solution, vous pouvez le faire en utilisant ResourceLoader comme ceci:

import org.springframework.core.io.Resource;
import org.Apache.commons.io.FileUtils;

@Autowire
private ResourceLoader resourceLoader;

...

Resource resource = resourceLoader.getResource("classpath:/path/to/you/dir");
File file = resource.getFile();
Iterator<File> fi = FileUtils.iterateFiles(file, null, true);
while(fi.hasNext()) {
    load(fi.next())
}
1
Qy Zuo

Simple ... utilisez OSGi. Dans OSGi, vous pouvez parcourir les entrées de votre lot avec findEntries et findPaths.

0
Peter Kriens