2009-03-24 17 views
110

¿Existe alguna forma en Java para construir una instancia de archivo en un recurso recuperado de un jar a través del cargador de clases?Recurso de Java como archivo

Mi aplicación utiliza algunos archivos del jar (predeterminado) o de un directorio del sistema de archivos especificado en el tiempo de ejecución (entrada del usuario). Estoy buscando una manera consistente de
a) carga estos archivos como una corriente
b) se enumeran los archivos en el directorio definido por el usuario o el directorio en el frasco, respectivamente

Editar: Al parecer, el enfoque ideal sería mantenerse alejado de java.io.File por completo. ¿Hay alguna manera de cargar un directorio desde la ruta de clases y enumerar sus contenidos (archivos/entidades contenidos en él)?

Respuesta

53

ClassLoader.getResourceAsStream y Class.getResourceAsStream son definitivamente el camino a seguir para cargar los datos del recurso. Sin embargo, no creo que haya ninguna forma de "enumerar" el contenido de un elemento de la ruta de clases.

En algunos casos esto puede ser simplemente imposible - por ejemplo, un ClassLoader podría generar datos sobre la marcha, en base a lo nombre del recurso que ha pedido. Si observas la API ClassLoader (que es básicamente lo que funciona el mecanismo classpath) verás que no hay nada para hacer lo que quieres.

Si sabe que tiene un archivo jar, puede cargarlo con ZipInputStream para averiguar qué hay disponible. Sin embargo, significará que tendrá un código diferente para directorios y archivos jar.

Una alternativa, si los archivos se crean por separado primero, es incluir un tipo de archivo de manifiesto que contiene la lista de recursos disponibles. Agrupe eso en el archivo jar o instálelo en el sistema de archivos como un archivo, y cárguelo antes de ofrecer al usuario una selección de recursos.

+3

Acepto que es molesto, pero hace que ClassLoader sea más extensamente aplicable de otras maneras. Por ejemplo, es fácil escribir un "cargador de clases web" porque la web es buena para buscar archivos, pero normalmente no * lista * archivos. –

+0

Parece que si el recurso que está intentando cargar es mucho más grande que 1Mib, el 'InputStream' que obtiene de' getResourceAsStream' se detiene para recuperar los bytes del recurso después de ese tamaño y en su lugar devuelve 0 iff está contenido en un sistema de archivos comprimido como un jarro Parece que se ve obligado a usar 'getResource' y cargar el archivo independientemente de esto en ese caso. – mgttlinger

+0

@mgttlinger: Eso me parece poco probable ... probablemente valga la pena publicar una nueva pregunta con una repro si puedes. –

5

Prueba esto:

ClassLoader.getResourceAsStream ("some/pkg/resource.properties"); 

hay más métodos disponibles, por ejemplo ver aquí: http://www.javaworld.com/javaworld/javaqa/2003-08/01-qa-0808-property.html

+0

Gracias por su respuesta. Sé sobre getResourceAsStream, pero no creo que pueda cargar un directorio desde el classpath hasta allí. – Mantrum

+0

En el directorio de Java hay un archivo (creo que las raíces de UNIX), así que al menos debería intentarlo. – topchef

+0

Creo que para listar los archivos en un directorio necesitarás usar java.io.File. Puede buscar archivos con ClassLoader.findResource que devuelve una URL que se puede pasar a File. –

91

que tenían el mismo problema y fue capaz de utilizar el siguiente:

// Load the directory as a resource 
URL dir_url = ClassLoader.getSystemResource(dir_path); 
// Turn the resource into a File object 
File dir = new File(dir_url.toURI()); 
// List the directory 
String files = dir.list() 
+37

Este enfoque no funciona con JAR en classpath, solo con archivos y directorios – yegor256

+1

¡Eso es lo que quiero! Realmente thx – StrikeW

+1

@ yegor256 Si su archivo está en un contenedor puede crear un objeto 'FileSystem' y obtener el' Path' de eso. Entonces puedes leerlo como de costumbre. (vea http://stackoverflow.com/a/22605905/1876344) – mgttlinger

2
+2

Si bien este enlace puede responder la pregunta, [sería preferible] (// meta.stackoverflow.com/q/8259) incluir las partes esenciales de la respuesta aquí, y proporcione el enlace para referencia, ya que un enlace puede cambiar o la página enlazada puede ser eliminada, haciendo que la respuesta sea inútil. – JonasCz

48

Aquí es un poco de código de una de mis aplicaciones ... Let si sé si se adapta a tus necesidades Puede usar esto si conoce el archivo que desea usar.

URL defaultImage = ClassA.class.getResource("/packageA/subPackage/image-name.png"); 
File imageFile = new File(defaultImage.toURI()); 

Espero que ayude.

9

Una forma segura para construir una instancia del archivo de un recurso obtenido de un frasco es para copiar el recurso como una corriente en un archivo temporal (se borra el archivo temporal cuando la JVM sale):

public static File getResourceAsFile(String resourcePath) { 
    try { 
     InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(resourcePath); 
     if (in == null) { 
      return null; 
     } 

     File tempFile = File.createTempFile(String.valueOf(in.hashCode()), ".tmp"); 
     tempFile.deleteOnExit(); 

     try (FileOutputStream out = new FileOutputStream(tempFile)) { 
      //copy stream 
      byte[] buffer = new byte[1024]; 
      int bytesRead; 
      while ((bytesRead = in.read(buffer)) != -1) { 
       out.write(buffer, 0, bytesRead); 
      } 
     } 
     return tempFile; 
    } catch (IOException e) { 
     e.printStackTrace(); 
     return null; 
    } 
} 
Cuestiones relacionadas