¿Cómo leer un archivo desde jar en Java?
Quiero leer un archivo XML que se encuentra dentro de uno de los jar
incluidos en mi ruta de clases. ¿Cómo puedo leer cualquier archivo que esté incluido en el jar
?
Si desea leer ese archivo desde el interior de su aplicación, utilice:
InputStream input = getClass().getResourceAsStream("/classpath/to/my/file");
La ruta comienza con "/", pero esa no es la ruta en su sistema de archivos, sino en su classpath. Entonces, si su archivo está en la ruta de clase "org.xml" y se llama myxml.xml, su ruta se verá así "/org/xml/myxml.xml".
InputStream lee el contenido de su archivo. Puedes incluirlo en un Reader, si lo deseas.
Ah, este es uno de mis temas favoritos. Básicamente, existen dos formas de cargar un recurso a través del classpath:
Class.getResourceAsStream(resource)
y
ClassLoader.getResourceAsStream(resource)
(Hay otras formas que implican obtener una URL para el recurso de manera similar y luego abrir una conexión a él, pero estas son las dos formas directas).
En realidad, el primer método delega en el segundo, después de alterar el nombre del recurso. Básicamente, existen dos tipos de nombres de recursos: absolutos (por ejemplo, "/ruta/a/recurso/recurso") y relativos (por ejemplo, "recurso"). Las rutas absolutas comienzan con "/".
He aquí un ejemplo que debería ilustrar. Considere una clase com.ejemplo.A. Considere dos recursos, uno ubicado en /com/example/nested y el otro en /top, en el classpath. El siguiente programa muestra nueve formas posibles de acceder a los dos recursos:
paquete com.ejemplo; clase pública A { público estático vacío principal (String args []) { // Clase.getResourceAsStream Recurso de objeto = A.class.getResourceAsStream("anidado"); System.out.println("1: A.class anidada=" + recurso); recurso = A.class.getResourceAsStream("/com/example/nested"); System.out.println("2: A.class /com/example/nested=" + recurso); recurso = A.class.getResourceAsStream("arriba"); System.out.println("3: A.class top=" + recurso); recurso = A.class.getResourceAsStream("/arriba"); System.out.println("4: A.class /top=" + recurso); // ClassLoader.getResourceAsStream ClassLoader cl = A.class.getClassLoader(); recurso = cl.getResourceAsStream("anidado"); System.out.println("5: cl nested=" + recurso); recurso = cl.getResourceAsStream("/com/example/nested"); System.out.println("6: cl /com/example/nested=" + recurso); recurso = cl.getResourceAsStream("com/example/nested"); System.out.println("7: cl com/example/nested=" + recurso); recurso = cl.getResourceAsStream("arriba"); System.out.println("8: cl top=" + recurso); recurso = cl.getResourceAsStream("/arriba"); System.out.println("9: cl /top=" + recurso); } }
La salida del programa es:
1: A.clase anidada = java.io.BufferedInputStream@19821f 2: A.clase /com/example/nested=java.io.BufferedInputStream@addbf1 3: A.clase superior = nula 4: A.clase /top=java.io.BufferedInputStream@42e816 5: cl anidado = nulo 6: cl /com/ejemplo/nested=null 7: cl com/example/nested=java.io.BufferedInputStream@9304b1 8: cl superior=java.io.BufferedInputStream@190d11 9: cl /arriba=nulo
La mayoría de las cosas hacen lo que esperarías. El Caso 3 falla porque la resolución relativa de la clase es con respecto a la Clase, por lo que "top" significa "/com/example/top", pero "/top" significa lo que dice.
El caso 5 falla porque la resolución relativa del cargador de clases es con respecto al cargador de clases. Pero, inesperadamente, el Caso 6 también falla: uno podría esperar que "/com/example/nested" se resuelva correctamente. Para acceder a un recurso anidado a través del cargador de clases, necesita usar el Caso 7, es decir, la ruta anidada es relativa a la raíz del cargador de clases. Del mismo modo, el Caso 9 falla, pero el Caso 8 pasa.
Recuerde: para java.lang.Class, getResourceAsStream() delega al cargador de clases:
público InputStream getResourceAsStream (nombre de cadena) { nombre = resolverNombre(nombre); ClassLoader cl = getClassLoader0(); si (cl==nulo) { // Una clase de sistema. devolver ClassLoader.getSystemResourceAsStream(nombre); } devolver cl.getResourceAsStream(nombre); }
entonces lo importante es el comportamiento de resolveName().
Finalmente, dado que es el comportamiento del cargador de clases el que cargó la clase lo que esencialmente controla getResourceAsStream(), y el cargador de clases es a menudo un cargador personalizado, entonces las reglas de carga de recursos pueden ser aún más complejas. por ejemplo, para aplicaciones web, cargue desde WEB-INF/classes o WEB-INF/lib en el contexto de la aplicación web, pero no desde otras aplicaciones web que estén aisladas. Además, los cargadores de clases con buen comportamiento delegan a los padres, por lo que es posible que no se pueda acceder a los recursos duplicados en el classpath mediante este mecanismo.