Java Language
Recursos (en classpath)
Buscar..
Introducción
Java permite la recuperación de recursos basados en archivos almacenados dentro de un JAR junto con las clases compiladas. Este tema se enfoca en cargar esos recursos y ponerlos a disposición de su código.
Observaciones
Un recurso son datos de tipo archivo con un nombre de ruta, que reside en la ruta de clase. El uso más común de los recursos es el agrupamiento de imágenes de aplicaciones, sonidos y datos de solo lectura (como la configuración predeterminada).
Se puede acceder a los recursos con los métodos ClassLoader.getResource y ClassLoader.getResourceAsStream . El caso de uso más común es tener recursos ubicados en el mismo paquete que la clase que los lee; los métodos Class.getResource y Class.getResourceAsStream sirven este caso de uso común.
La única diferencia entre un método getResource y un método getResourceAsStream es que el primero devuelve una URL, mientras que el segundo abre esa URL y devuelve un InputStream.
Los métodos de ClassLoader aceptan un nombre de recurso similar a una ruta como un argumento y buscan en cada ubicación en la ruta de clases del ClassLoader una entrada que coincida con ese nombre.
- Si una ubicación de classpath es un archivo .jar, una entrada jar con el nombre especificado se considera una coincidencia.
- Si una ubicación de classpath es un directorio, un archivo relativo debajo de ese directorio con el nombre especificado se considera una coincidencia.
El nombre del recurso es similar a la porción de ruta de una URL relativa. En todas las plataformas, utiliza barras diagonales ( /
) como separadores de directorios. No debe comenzar con una barra.
Los métodos de clase correspondientes son similares, excepto:
- El nombre del recurso puede comenzar con una barra inclinada, en cuyo caso esa barra inicial se elimina y el resto del nombre se pasa al método correspondiente de ClassLoader.
- Si el nombre del recurso no comienza con una barra diagonal, se trata en relación con la clase a la que se llama el método getResource o getResourceAsStream. El nombre del recurso real se convierte en paquete / nombre , donde paquete es el nombre del paquete al que pertenece la clase, con cada período reemplazado por una barra y nombre es el argumento original dado al método.
Por ejemplo:
package com.example;
public class ExampleApplication {
public void readImage()
throws IOException {
URL imageURL = ExampleApplication.class.getResource("icon.png");
// The above statement is identical to:
// ClassLoader loader = ExampleApplication.class.getClassLoader();
// URL imageURL = loader.getResource("com/example/icon.png");
Image image = ImageIO.read(imageURL);
}
}
Los recursos deben colocarse en paquetes con nombre, en lugar de en la raíz de un archivo .jar, por la misma razón que las clases se colocan en paquetes: para evitar colisiones entre varios proveedores. Por ejemplo, si hay varios archivos .jar en la ruta de clase, y más de uno de ellos contiene una entrada config.properties
en su raíz, las llamadas a los métodos getResource o getResourceAsStream devolverán las config.properties de cualquiera que sea .jar aparece primero en el classpath Este no es un comportamiento predecible en entornos donde el orden de la ruta de clase no está bajo el control directo de la aplicación, como Java EE.
Todos los métodos getResource y getResourceAsStream devuelven un null
si el recurso especificado no existe. Dado que los recursos deben agregarse a la aplicación en el momento de la compilación, sus ubicaciones deben ser conocidas cuando se escribe el código; un error al no encontrar un recurso en tiempo de ejecución suele ser el resultado de un error del programador.
Los recursos son de solo lectura. No hay forma de escribir en un recurso. Los desarrolladores novatos a menudo cometen el error de suponer que, dado que el recurso es un archivo físico independiente cuando se desarrolla en un IDE (como Eclipse), será seguro tratarlo como un archivo físico separado en el caso general. Sin embargo, esto no es correcto; las aplicaciones casi siempre se distribuyen como archivos .jar o archivos .war, y en tales casos, un recurso no será un archivo separado y no se podrá escribir. (El método getFile de la clase de URL no es una solución para esto; a pesar de su nombre, simplemente devuelve la parte de la ruta de una URL, que de ninguna manera se garantiza que sea un nombre de archivo válido).
No hay una forma segura de enumerar los recursos en tiempo de ejecución. Nuevamente, dado que los desarrolladores son responsables de agregar archivos de recursos a la aplicación en el momento de la compilación, los desarrolladores ya deben conocer sus rutas. Si bien hay soluciones alternativas, no son confiables y eventualmente fallarán.
Cargando una imagen de un recurso
Para cargar una imagen agrupada:
package com.example;
public class ExampleApplication {
private Image getIcon() throws IOException {
URL imageURL = ExampleApplication.class.getResource("icon.png");
return ImageIO.read(imageURL);
}
}
Cargando la configuración por defecto
Para leer las propiedades de configuración por defecto:
package com.example;
public class ExampleApplication {
private Properties getDefaults() throws IOException {
Properties defaults = new Properties();
try (InputStream defaultsStream =
ExampleApplication.class.getResourceAsStream("config.properties")) {
defaults.load(defaultsStream);
}
return defaults;
}
}
Cargando recursos del mismo nombre desde múltiples archivos JAR
El recurso con la misma ruta y nombre puede existir en más de un archivo JAR en la ruta de clase. Los casos comunes son recursos que siguen una convención o que son parte de una especificación de empaquetado. Ejemplos de tales recursos son
- META-INF / MANIFEST.MF
- META-INF / beans.xml (CDI Spec)
- Propiedades de ServiceLoader que contienen proveedores de implementación
Para obtener acceso a todos estos recursos en diferentes tarros, uno tiene que usar un ClassLoader, que tiene un método para esto. La Enumeration
devuelta se puede convertir convenientemente en una List
mediante una función de colecciones.
Enumeration<URL> resEnum = MyClass.class.getClassLoader().getResources("META-INF/MANIFEST.MF");
ArrayList<URL> resources = Collections.list(resEnum);
Encontrar y leer recursos usando un cargador de clases
La carga de recursos en Java comprende los siguientes pasos:
- Encontrar la
Class
oClassLoader
que encontrará el recurso. - Encontrar el recurso.
- Obtención del flujo de bytes para el recurso.
- Lectura y procesamiento del flujo de bytes.
- Cierre de la corriente de bytes.
Los últimos tres pasos se realizan normalmente al pasar la URL a un método de biblioteca o un constructor para cargar el recurso. Normalmente utilizarás un método getResource
en este caso. También es posible leer los datos del recurso en el código de la aplicación. En este caso, normalmente getResourceAsStream
.
Rutas de recursos absolutos y relativos
Los recursos que se pueden cargar desde la ruta de clase se indican mediante una ruta . La sintaxis de la ruta es similar a la ruta de un archivo UNIX / Linux. Consiste en nombres simples separados por caracteres de barra ( /
). Una ruta relativa comienza con un nombre y una ruta absoluta comienza con un separador.
Como describen los ejemplos de Classpath, la classpath de una JVM define un espacio de nombres superponiendo los espacios de nombres de los directorios y los archivos JAR o ZIP en la classpath. Cuando se resuelve una ruta absoluta, los cargadores de clases interpretan la inicial /
como la raíz del espacio de nombres. Por el contrario, una ruta relativa puede resolverse en relación con cualquier "carpeta" en el espacio de nombres. La carpeta utilizada dependerá del objeto que utilice para resolver la ruta.
Obtención de una Clase o Classloader
Un recurso se puede ubicar utilizando un objeto Class
o un objeto ClassLoader
. Un objeto de Class
puede resolver rutas relativas, por lo que normalmente usará una de estas si tiene un recurso relativo (clase). Hay varias formas de obtener un objeto de Class
. Por ejemplo:
Un literal de clase le dará el objeto de
Class
para cualquier clase que pueda nombrar en el código fuente de Java; por ejemplo,String.class
te da el objetoClass
para el tipoString
.El
Object.getClass()
le dará el objetoClass
para el tipo od cualquier objeto; por ejemplo,"hello".getClass()
es otra forma de obtener laClass
del tipoString
.El método
Class.forName(String)
(si es necesario) cargará dinámicamente una clase y devolverá su objetoClass
; por ejemplo,Class.forName("java.lang.String")
.
Un objeto ClassLoader
se obtiene normalmente llamando a getClassLoader()
en un objeto Class
. También es posible obtener el cargador de clases predeterminado de la JVM utilizando el método estático ClassLoader.getSystemClassLoader()
.
Los metodos de get
Una vez que tenga una instancia de Class
o ClassLoader
, puede encontrar un recurso, usando uno de los siguientes métodos:
Métodos | Descripción |
---|---|
ClassLoader.getResource(path) ClassLoader.getResources(path) | Devuelve una URL que representa la ubicación del recurso con la ruta dada. |
ClassLoader.getResources(path) Class.getResources(path) | Devuelve una Enumeration<URL> proporciona las URL que se pueden usar para ubicar el recurso foo.bar ; vea abajo. |
ClassLoader.getResourceAsStream(path) Class.getResourceStream(path) | Devuelve un InputStream desde el cual puede leer el contenido del recurso foo.bar como una secuencia de bytes. |
Notas:
La principal diferencia entre las versiones
ClassLoader
yClass
de los métodos se encuentra en la forma en que se interpretan las rutas relativas.- Los métodos de
Class
resuelven una ruta relativa en la "carpeta" que corresponde al paquete de clases. - Los métodos de
ClassLoader
tratan las rutas relativas como si fueran absolutas; es decir, resolverlos en la "carpeta raíz" del espacio de nombres de classpath.
- Los métodos de
Si no se puede encontrar el recurso (o recursos) solicitado, los
methods return
getResource
y getResourceAsStreammethods return
valor nulo, and the
methods return an empty
getResourcesmethods return an empty
Enumeraciónmethods return an empty
.Las URL devueltas se podrán resolver mediante
URL.toStream()
. Pueden serfile:
URL u otras URL convencionales, pero si el recurso reside en un archivo JAR, seránjar:
URL que identifican el archivo JAR y un recurso específico dentro de él.Si su código utiliza un método
getResourceAsStream
(oURL.toStream()
) para obtener unInputStream
, es responsable de cerrar el objeto de flujo. Si no se cierra el flujo, podría producirse una fuga de recursos.