Comment lire un fichier à partir de jar en Java?

Je souhaite lire un fichier XML situé dans l’un des fichiers jar inclus dans mon chemin de classe. Comment lire un fichier inclus dans le fichier jar ?

Si vous voulez lire ce fichier depuis l’intérieur de votre application, utilisez:

 InputStream input = getClass().getResourceAsStream("/classpath/to/my/file"); 

Le chemin commence par “/”, mais ce n’est pas le chemin dans votre système de fichiers, mais dans votre chemin de classe. Donc, si votre fichier se trouve dans le classpath “org.xml” et s’appelle myxml.xml, votre chemin ressemble à “/org/xml/myxml.xml”.

Le InputStream lit le contenu de votre fichier. Vous pouvez l’envelopper dans un lecteur, si vous le souhaitez.

J’espère que ça aide.

Ah, c’est l’un de mes sujets préférés. Il existe essentiellement deux manières de charger une ressource via le chemin de classe:

 Class.getResourceAsStream(resource) 

et

 ClassLoader.getResourceAsStream(resource) 

(Il existe d’autres moyens pour obtenir une URL de la même manière, puis pour y ouvrir une connexion, mais ce sont les deux méthodes directes).

La première méthode délègue réellement à la seconde, après avoir gommé le nom de la ressource. Il existe essentiellement deux types de noms de ressources: absolus (par exemple “/ chemin / vers / ressource / ressource”) et relatifs (par exemple “ressource”). Les chemins absolus commencent par “/”.

Voici un exemple qui devrait illustrer. Considérons une classe com.example.A. Considérons deux ressources, l’une située dans / com / example / nested, l’autre dans / top, dans le classpath. Le programme suivant montre neuf façons possibles d’accéder aux deux ressources:

 package com.example;

 classe publique A {

     main statique statique vide (Ssortingng args []) {

         // Class.getResourceAsStream
         Ressource d'object = A.class.getResourceAsStream ("nested");
         System.out.println ("1: A.class nested =" + ressource);

         resource = A.class.getResourceAsStream ("/ com / example / nested");
         System.out.println ("2: A.class / com / example / nested =" + ressource);

         resource = A.class.getResourceAsStream ("top");
         System.out.println ("3: A.class top =" + ressource);

         resource = A.class.getResourceAsStream ("/ top");
         System.out.println ("4: A.class / top =" + ressource);

         // ClassLoader.getResourceAsStream
         ClassLoader cl = A.class.getClassLoader ();
         resource = cl.getResourceAsStream ("nested");        
         System.out.println ("5: cl nested =" + ressource);

         resource = cl.getResourceAsStream ("/ com / example / nested");
         System.out.println ("6: cl / com / example / nested =" + ressource);
         resource = cl.getResourceAsStream ("com / example / nested");
         System.out.println ("7: cl com / example / nested =" + ressource);

         resource = cl.getResourceAsStream ("top");
         System.out.println ("8: cl top =" + ressource);

         resource = cl.getResourceAsStream ("/ top");
         System.out.println ("9: cl / top =" + ressource);
     }

 }

Le résultat du programme est le suivant:

 1: A.class nested=java.io.BufferedInputStream@19821f
 2: A.class /com/example/nested=java.io.BufferedInputStream@addbf1
 3: A.class top = null
 4: A.class /top=java.io.BufferedInputStream@42e816
 5: cl nested = null
 6: cl / com / example / nested = null
 7: cl com/example/nested=java.io.BufferedInputStream@9304b1
 8: cl top=java.io.BufferedInputStream@190d11
 9: cl / top = null

La plupart des choses font ce que vous attendez. Le cas 3 échoue parce que la résolution relative à la classe concerne la classe, donc “top” signifie “/ com / example / top”, mais “/ top” signifie ce qu’il dit.

Le cas 5 échoue parce que la résolution relative du chargeur de classe est liée au chargeur de classes. Mais, de manière inattendue, Case-6 échoue également: on peut s’attendre à ce que “/ com / example / nested” soit résolu correctement. Pour accéder à une ressource nestede via le chargeur de classes, vous devez utiliser Case-7, c’est-à-dire que le chemin nested est relatif à la racine du chargeur de classes. De même, le cas 9 échoue, mais le cas 8 passe.

Rappelez-vous: pour java.lang.Class, getResourceAsStream () délègue au classloader:

      Public InputStream getResourceAsStream (Nom de la chaîne) {
         name = resolveName (name);
         ClassLoader cl = getClassLoader0 ();
         si (cl == null) {
             // Une classe système.
             retourne ClassLoader.getSystemResourceAsStream (name);
         }
         retourne cl.getResourceAsStream (name);
     }

c’est donc le comportement de resolveName () qui est important.

Enfin, comme c’est le comportement du classloader qui a chargé la classe qui contrôle essentiellement getResourceAsStream () et que le chargeur de classe est souvent un chargeur personnalisé, les règles de chargement des ressources peuvent être encore plus complexes. Par exemple, pour les applications Web, chargez depuis WEB-INF / classes ou WEB-INF / lib dans le contexte de l’application Web, mais pas à partir d’autres applications Web isolées. De même, les chargeurs de classe bien comportés délèguent aux parents, de sorte que les ressources dupliquées dans le chemin de classes ne soient pas accessibles à l’aide de ce mécanisme.

Vérifiez d’abord votre chargeur de classe.

 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); if (classLoader == null) { classLoader = Class.class.getClassLoader(); } classLoader.getResourceAsStream("xmlFileNameInJarFile.xml"); // xml file location at xxx.jar // + folder // + folder // xmlFileNameInJarFile.xml 

Un fichier JAR est essentiellement un fichier ZIP. Traitez-le comme tel. Vous trouverez ci-dessous un exemple sur la façon d’extraire un fichier d’un fichier WAR (le traiter également comme un fichier ZIP) et d’afficher le contenu de la chaîne. Pour le binary, vous devrez modifier le processus d’extraction, mais vous trouverez de nombreux exemples.

 public static void main(Ssortingng args[]) { Ssortingng relativeFilePath = "style/someCSSFile.css"; Ssortingng zipFilePath = "/someDirectory/someWarFile.war"; Ssortingng contents = readZipFile(zipFilePath,relativeFilePath); System.out.println(contents); } public static Ssortingng readZipFile(Ssortingng zipFilePath, Ssortingng relativeFilePath) { try { ZipFile zipFile = new ZipFile(zipFilePath); Enumeration e = zipFile.ensortinges(); while (e.hasMoreElements()) { ZipEntry entry = (ZipEntry) e.nextElement(); // if the entry is not directory and matches relative file then extract it if (!entry.isDirectory() && entry.getName().equals(relativeFilePath)) { BufferedInputStream bis = new BufferedInputStream( zipFile.getInputStream(entry)); // Read the file // With Apache Commons I/O Ssortingng fileContentsStr = IOUtils.toSsortingng(bis, "UTF-8"); // With Guava //Ssortingng fileContentsStr = new Ssortingng(ByteStreams.toByteArray(bis),Charsets.UTF_8); // close the input stream. bis.close(); return fileContentsStr; } else { continue; } } } catch (IOException e) { logger.error("IOError :" + e); e.printStackTrace(); } return null; } 

Dans cet exemple, j’utilise Apache Commons I / O et si vous utilisez Maven, voici la dépendance:

  commons-io commons-io 2.4  

Pour être complet, il y a eu récemment une question sur la liste de diffusion Jython où l’une des réponses faisait référence à ce sujet.

La question était de savoir comment appeler un script Python contenu dans un fichier .jar depuis Jython, la réponse suggérée est la suivante (avec “InputStream” comme expliqué dans l’une des réponses ci-dessus:

 PythonInterpreter.execfile(InputStream)