recursos proyecto obtener leer dentro archivo java file jar resources

java - proyecto - Lectura de un archivo de recursos desde dentro de jar



leer recursos java (9)

Asegúrese de trabajar con el separador correcto. File.separator todo / en una ruta relativa con un File.separator . Esto funcionó bien en el IDE, sin embargo no funcionó en el JAR de compilación.

Me gustaría leer un recurso dentro de mi jar como lo hace:

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

y funciona bien cuando se ejecuta en Eclipse, pero si lo exporto a un archivo jar, ejecútelo con IllegalArgumentException:

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

y realmente no sé por qué, pero con algunas pruebas que encontré si cambio

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

a

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

luego funciona al revés (funciona en jar pero no en eclipse).

Estoy usando Eclipse y la carpeta con mi archivo es una carpeta de clase.


Después de investigar mucho en Java, la única solución que parece funcionar para mí es leer manualmente el archivo jar a menos que esté en un entorno de desarrollo (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 * <b><code>null</code></b> if the resource does not exist */ public static final InputStream getResourceAsStream(String resource) { resource = resource.startsWith("/") ? resource : "/" + resource; if(getClasspathFile().isDirectory()) {//Development environment: return YourMainClass.class.getResourceAsStream(resource); } final String res = resource;//Jar or exe: return AccessController.doPrivileged(new PrivilegedAction<InputStream>() { @SuppressWarnings("resource") @Override public InputStream run() { try { final JarFile jar = new JarFile(getClasspathFile()); String resource = res.startsWith("/") ? res.substring(1) : res; if(resource.endsWith("/")) {//Directory; list direct contents:(Mimics normal getResourceAsStream("someFolder/") behaviour) ByteArrayOutputStream baos = new ByteArrayOutputStream(); Enumeration<JarEntry> entries = jar.entries(); while(entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); if(entry.getName().startsWith(resource) && entry.getName().length() > resource.length()) { String name = entry.getName().substring(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.substring(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; } } }); }

Nota: El código anterior solo parece funcionar correctamente para archivos jar si está en la clase principal. No estoy seguro por qué.


En lugar de intentar direccionar el recurso como un File simplemente solicite a ClassLoader que devuelva un InputStream para el recurso a través de getResourceAsStream :

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

Siempre que el recurso file.txt esté disponible en el classpath, este enfoque funcionará de la misma manera independientemente de si el recurso file.txt está en un directorio de classes/ o dentro de un jar .

El URI is not hierarchical porque el URI de un recurso dentro de un archivo jar se verá así: file:/example.jar!/file.txt . No puede leer las entradas dentro de un jar (un archivo zip ) como si fuera un File antiguo.

Esto se explica bien por las respuestas a:


Hasta ahora (diciembre de 2017), esta es la única solución que encontré que funciona tanto dentro como fuera del IDE.

Use PathMatchingResourcePatternResolver

Nota: funciona también en spring-boot

En este ejemplo, estoy leyendo algunos archivos ubicados en src / main / resources / my_folder :

try { // Get all the files under this inner resource folder: my_folder String 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())); String line = null; while ((line = bufferedReader.readLine()) != null) { // ... // ... } bufferedReader.close(); } } } catch (Exception e) { throw new Exception("Failed to read the resources folder: " + e.getMessage(), e); }


Para acceder a un archivo en un contenedor, tiene dos opciones:

  • Coloque el archivo en la estructura de directorios que coincida con el nombre de su paquete (después de extraer el archivo .jar, debe estar en el mismo directorio que el archivo .class), luego acceda a él usando getClass().getResourceAsStream("file.txt")

  • Coloque el archivo en la raíz (después de extraer el archivo .jar, debe estar en la raíz), luego acceda a él usando Thread.currentThread().getContextClassLoader().getResourceAsStream("file.txt")

La primera opción puede no funcionar cuando jar se usa como un complemento.


Si está utilizando la primavera, puede usar el siguiente método para leer el archivo de 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 String readFile() { StringBuilder result = new StringBuilder(""); ClassPathResource resource = new ClassPathResource("filename.txt"); try (InputStream inputStream = resource.getInputStream()) { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); String line; while ((line = bufferedReader.readLine()) != null) { result.append(line); } inputStream.close(); } catch (IOException e) { e.printStackTrace(); } return result.toString(); }


Si quieres leer como un archivo, creo que todavía hay una solución similar:

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


También puedes usar java.nio. Aquí hay un ejemplo para sorber texto de un archivo en resourcePath en classpath:

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


Tuve este problema antes y lo hice de forma alternativa para cargarlo. Básicamente, la primera forma de trabajo dentro del archivo .jar y la segunda vía funciona dentro de Eclipse u otro IDE.

public class MyClass { public static InputStream accessFile() { String 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; } }