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:

  1. Encontrar la Class o ClassLoader que encontrará el recurso.
  2. Encontrar el recurso.
  3. Obtención del flujo de bytes para el recurso.
  4. Lectura y procesamiento del flujo de bytes.
  5. 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 objeto Class para el tipo String .

  • El Object.getClass() le dará el objeto Class para el tipo od cualquier objeto; por ejemplo, "hello".getClass() es otra forma de obtener la Class del tipo String .

  • El método Class.forName(String) (si es necesario) cargará dinámicamente una clase y devolverá su objeto Class ; 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 y Class 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.
  • Si no se puede encontrar el recurso (o recursos) solicitado, los methods return getResource y getResourceAsStream methods return valor nulo , and the methods return an empty getResources methods return an empty Enumeración methods return an empty .

  • Las URL devueltas se podrán resolver mediante URL.toStream() . Pueden ser file: URL u otras URL convencionales, pero si el recurso reside en un archivo JAR, serán jar: URL que identifican el archivo JAR y un recurso específico dentro de él.

  • Si su código utiliza un método getResourceAsStream (o URL.toStream() ) para obtener un InputStream , es responsable de cerrar el objeto de flujo. Si no se cierra el flujo, podría producirse una fuga de recursos.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow