Lecture d’un fichier de ressources depuis jar

Je voudrais lire une ressource de mon pot ainsi:

File file; file = new File(getClass().getResource("/file.txt").toURI()); BufferredReader reader = new BufferedReader(new FileReader(file)); //Read the file 

et ça marche bien quand on l’exécute dans Eclipse, mais si je l’exporte dans un fichier jar, il y a une exception IllegalArgumentException:

 Exception in thread "Thread-2" java.lang.IllegalArgumentException: URI is not hierarchical 

et je ne sais vraiment pas pourquoi mais avec quelques tests, j’ai trouvé si je change

 file = new File(getClass().getResource("/file.txt").toURI()); 

à

 file = new File(getClass().getResource("/folder/file.txt").toURI()); 

alors ça marche au contraire (ça marche en pot mais pas en éclipse).

J’utilise Eclipse et le dossier contenant mon fichier est un dossier de classe.

Plutôt que d’essayer d’adresser la ressource en tant que fichier, demandez simplement au ClassLoader de renvoyer un InputStream pour la ressource via getResourceAsStream :

 InputStream in = getClass().getResourceAsStream("/file.txt"); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); 

Tant que la ressource file.txt est disponible sur le chemin de classes/ cette approche fonctionnera de la même manière, que la ressource file.txt soit dans un répertoire classes/ ou dans un jar .

L’ URI is not hierarchical car l’URI d’une ressource dans un fichier jar va ressembler à ceci: file:/example.jar!/file.txt . Vous ne pouvez pas lire les entrées dans un fichier jar (un fichier zip ) comme s’il s’agissait d’un ancien fichier .

Cela s’explique bien par les réponses à:

  • Comment lire un fichier de ressources à partir d’un fichier jar Java?
  • Fichier Java Jar: utiliser des erreurs de ressources: l’URI n’est pas hiérarchique

Pour accéder à un fichier dans un pot, vous avez deux options:

  • Placez le fichier dans la structure de répertoires correspondant au nom de votre package (après avoir extrait le fichier .jar, il doit se trouver dans le même répertoire que le fichier .class), puis accédez-y à l’aide de getClass().getResourceAsStream("file.txt")

  • Placez le fichier à la racine (après avoir extrait le fichier .jar, il doit se trouver à la racine), puis accédez-y à l’aide de Thread.currentThread().getContextClassLoader().getResourceAsStream("file.txt")

La première option peut ne pas fonctionner lorsque jar est utilisé comme plug-in.

Si vous voulez lire en tant que fichier, je pense qu’il existe toujours une solution similaire:

  ClassLoader classLoader = getClass().getClassLoader(); File file = new File(classLoader.getResource("file/test.xml").getFile()); 

Vous pouvez également utiliser java.nio. Voici un exemple de slurp dans le texte d’un fichier à resourcePath dans classpath:

 new Ssortingng(Files.readAllBytes(Paths.get(getClass().getResource(resourcePath).toURI()))) 

Assurez-vous que vous travaillez avec le séparateur correct. J’ai remplacé tout / dans un chemin relatif par un File.separator . Cela a bien fonctionné dans l’EDI, mais n’a pas fonctionné dans le JAR de compilation.

J’ai eu ce problème avant et j’ai fait la voie de secours pour le chargement. Fondamentalement, le premier moyen de travailler dans le fichier .jar et la seconde méthode fonctionne dans eclipse ou autre IDE.

 public class MyClass { public static InputStream accessFile() { Ssortingng resource = "my-file-located-in-resources.txt"; // this is the path within the jar file InputStream input = MyClass.class.getResourceAsStream("/resources/" + resource); if (input == null) { // this is how we load file within editor (eg eclipse) input = MyClass.class.getClassLoader().getResourceAsStream(resource); } return input; } } 

Si vous utilisez Spring, vous pouvez utiliser la méthode suivante pour lire le fichier depuis src / main / resources:

 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import org.springframework.core.io.ClassPathResource; public Ssortingng readFile() { SsortingngBuilder result = new SsortingngBuilder(""); ClassPathResource resource = new ClassPathResource("filename.txt"); try (InputStream inputStream = resource.getInputStream()) { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); Ssortingng line; while ((line = bufferedReader.readLine()) != null) { result.append(line); } inputStream.close(); } catch (IOException e) { e.printStackTrace(); } return result.toSsortingng(); } 

Jusqu’à présent (décembre 2017), c’est la seule solution trouvée qui fonctionne à la fois à l’ intérieur et à l’extérieur de l’EDI.

Utilisez PathMatchingResourcePatternResolver

Note: ça marche aussi dans la botte de spring

Dans cet exemple, je lis des fichiers situés dans src / main / resources / my_folder :

 try { // Get all the files under this inner resource folder: my_folder Ssortingng scannedPackage = "my_folder/*"; PathMatchingResourcePatternResolver scanner = new PathMatchingResourcePatternResolver(); Resource[] resources = scanner.getResources(scannedPackage); if (resources == null || resources.length == 0) log.warn("Warning: could not find any resources in this scanned package: " + scannedPackage); else { for (Resource resource : resources) { log.info(resource.getFilename()); // Read the file content (I used BufferedReader, but there are other solutions for that): BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(resource.getInputStream())); Ssortingng line = null; while ((line = bufferedReader.readLine()) != null) { // ... // ... } bufferedReader.close(); } } } catch (Exception e) { throw new Exception("Failed to read the resources folder: " + e.getMessage(), e); } 

Après beaucoup de recherches en Java, la seule solution qui semble fonctionner pour moi est de lire manuellement le fichier jar lui-même, sauf si vous vous trouvez dans un environnement de développement (IDE):

 /** @return The root folder or jar file that the class loader loaded from */ public static final File getClasspathFile() { return new File(YourMainClass.class.getProtectionDomain().getCodeSource().getLocation().getFile()); } /** @param resource The path to the resource * @return An InputStream containing the resource's contents, or * null if the resource does not exist */ public static final InputStream getResourceAsStream(Ssortingng resource) { resource = resource.startsWith("/") ? resource : "/" + resource; if(getClasspathFile().isDirectory()) {//Development environment: return YourMainClass.class.getResourceAsStream(resource); } final Ssortingng res = resource;//Jar or exe: return AccessController.doPrivileged(new PrivilegedAction() { @SuppressWarnings("resource") @Override public InputStream run() { try { final JarFile jar = new JarFile(getClasspathFile()); Ssortingng resource = res.startsWith("/") ? res.subssortingng(1) : res; if(resource.endsWith("/")) {//Directory; list direct contents:(Mimics normal getResourceAsStream("someFolder/") behaviour) ByteArrayOutputStream baos = new ByteArrayOutputStream(); Enumeration ensortinges = jar.ensortinges(); while(ensortinges.hasMoreElements()) { JarEntry entry = ensortinges.nextElement(); if(entry.getName().startsWith(resource) && entry.getName().length() > resource.length()) { Ssortingng name = entry.getName().subssortingng(resource.length()); if(name.contains("/") ? (name.endsWith("/") && (name.indexOf("/") == name.lastIndexOf("/"))) : true) {//If it's a folder, we don't want the children's folders, only the parent folder's children! name = name.endsWith("/") ? name.subssortingng(0, name.length() - 1) : name; baos.write(name.getBytes(StandardCharsets.UTF_8)); baos.write('\r'); baos.write('\n'); } } } jar.close(); return new ByteArrayInputStream(baos.toByteArray()); } JarEntry entry = jar.getJarEntry(resource); InputStream in = entry != null ? jar.getInputStream(entry) : null; if(in == null) { jar.close(); return in; } final InputStream stream = in;//Don't manage 'jar' with try-with-resources or close jar until the return new InputStream() {//returned stream is closed(closing the jar closes all associated InputStreams): @Override public int read() throws IOException { return stream.read(); } @Override public int read(byte b[]) throws IOException { return stream.read(b); } @Override public int read(byte b[], int off, int len) throws IOException { return stream.read(b, off, len); } @Override public long skip(long n) throws IOException { return stream.skip(n); } @Override public int available() throws IOException { return stream.available(); } @Override public void close() throws IOException { try { jar.close(); } catch(IOException ignored) { } stream.close(); } @Override public synchronized void mark(int readlimit) { stream.mark(readlimit); } @Override public synchronized void reset() throws IOException { stream.reset(); } @Override public boolean markSupported() { return stream.markSupported(); } }; } catch(Throwable e) { e.printStackTrace(); return null; } } }); } 

Remarque: Le code ci-dessus ne semble fonctionner correctement que pour les fichiers jar s’il se trouve dans la classe principale. Je ne sais pas pourquoi.