2009-03-24 20 views
110

C'è un modo in Java per costruire un'istanza File su una risorsa recuperata da un jar attraverso il classloader?Risorsa Java come file

La mia applicazione utilizza alcuni file dal jar (predefinito) o da una directory del filesystem specificata in fase di esecuzione (input dell'utente). Sto cercando un modo coerente di
a) carico questi file come un flusso
b) sfogliare i file nella directory definita dall'utente o la directory nel vaso, rispettivamente

Edit: A quanto pare, l'approccio ideale sarebbe di stare lontano da java.io.File del tutto. C'è un modo per caricare una directory dal classpath ed elencarne il contenuto (file/entità contenuti in essa)?

risposta

53

ClassLoader.getResourceAsStream e Class.getResourceAsStream sono sicuramente la strada da percorrere per il caricamento dei dati delle risorse. Tuttavia, non credo che esista un modo per "elencare" il contenuto di un elemento del classpath.

In alcuni casi questo può essere semplicemente impossibile - per esempio, un ClassLoaderpotrebbe generare i dati al volo, in base a ciò nome della risorsa è chiesto. Se si guarda l'API ClassLoader (che è fondamentalmente il modo in cui funziona il meccanismo del classpath) vedrete che non c'è niente da fare ciò che volete.

Se sai che hai effettivamente un file jar, puoi caricarlo con ZipInputStream per scoprire cosa è disponibile. Significa che avrai comunque un codice diverso per le directory e i file jar.

Un'alternativa, se i file vengono creati separatamente per primi, deve includere una sorta di file manifest contenente l'elenco delle risorse disponibili. Raggruppalo nel file jar o includilo nel file system come un file e caricalo prima di offrire all'utente una scelta di risorse.

+3

Sono d'accordo che è fastidioso, ma rende ClassLoader più ampiamente applicabile in altri modi. Ad esempio, è facile scrivere un "web classloader" perché il web è adatto per il recupero dei file, ma generalmente non * elenca * i file. –

+0

Sembra che la risorsa che si sta tentando di caricare sia molto più grande di 1MiB il 'InputStream' che si ottiene dagli arresti' getResourceAsStream' per recuperare i byte della risorsa dopo quella dimensione e invece restituisce 0 se è contenuto in un filesystem compresso come un barattolo Sembra che tu sia obbligato a usare 'getResource' e caricare il file indipendentemente da questo in quel caso. – mgttlinger

+0

@mgttlinger: Mi sembra improbabile che valga la pena di postare una nuova domanda con una repro, se possibile. –

5

Prova questo:

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

Non ci sono altri metodi disponibili, per esempio Vedi qui: http://www.javaworld.com/javaworld/javaqa/2003-08/01-qa-0808-property.html

+0

Grazie per la risposta. So getResourceAsStream, ma non penso di poter caricare una directory dal classpath attraverso quella. – Mantrum

+0

Nella directory Java è un file (radici UNIX immagino) quindi dovresti almeno provarci. – topchef

+0

Penso di elencare i file in una directory che dovrai usare java.io.File. Puoi cercare i file con ClassLoader.findResource che restituisce un URL che può essere passato a File. –

91

Ho avuto lo stesso problema ed è stato in grado di utilizzare il seguente:

// 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

Questo approccio non funziona con JAR in classpath, solo con file e directory – yegor256

+1

Questo è quello che voglio! really thx – StrikeW

+1

@ yegor256 Se il tuo file è in un jar puoi creare un oggetto 'FileSystem' e ottenere il' Path' da quello. Quindi puoi leggerlo come al solito. (vedi http://stackoverflow.com/a/22605905/1876344) – mgttlinger

2
+2

Mentre questo link può rispondere alla domanda, [sarebbe preferibile] (// meta.stackoverflow.com/q/8259) per includere le parti essenziali di la risposta qui e fornire il collegamento per riferimento, come un collegamento può cambiare o la pagina collegata può essere rimossa, rendendo in tal modo la risposta inutile. – JonasCz

48

Ecco un po 'di codice da una delle mie applicazioni ... Let so se si adatta alle tue esigenze. È possibile utilizzare questo se si conosce il file che si desidera utilizzare.

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

Spero che questo aiuti.

9

un modo affidabile per costruire un'istanza di file a una risorsa recuperata da un vaso è per copiare la risorsa come un flusso in un file temporaneo (il file temporaneo verrà cancellato quando la JVM esce):

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; 
    } 
} 
Problemi correlati