risorsa aperta con percorso relativo in Java


84

Nella mia app Java ho bisogno di ottenere alcuni file e directory.

Questa è la struttura del programma:

./main.java
./package1/guiclass.java
./package1/resources/resourcesloader.java
./package1/resources/repository/modules/   -> this is the dir I need to get
./package1/resources/repository/SSL-Key/cert.jks    -> this is the file I need to get

guiclass carica la classe resourcesloader che caricherà le mie risorse (directory e file).

Per quanto riguarda il file, ho provato

resourcesloader.class.getClass().getResource("repository/SSL-Key/cert.jks").toString()

per ottenere il percorso reale, ma in questo modo non funziona.

Non ho idea di quale percorso utilizzare per la directory.


1
class.getClass () non è la stessa di class.getClassLoader (). C'è anche un'altra soluzione, getResourceAsStream () che usa una classe nello stesso pacchetto della tua risorsa. Per maggiori dettagli: tshikatshikaaa.blogspot.nl/2012/07/… .
Jérôme Verstrynge

Risposte:


48

Fornisci il percorso relativo al caricatore di classi, non la classe da cui stai ricevendo il caricatore. Per esempio:

resourcesloader.class.getClassLoader().getResource("package1/resources/repository/SSL-Key/cert.jks").toString();

161

Ho avuto problemi con l'utilizzo del getClass().getResource("filename.txt")metodo. Dopo aver letto le istruzioni della documentazione Java, se la tua risorsa non si trova nello stesso pacchetto della classe dalla quale stai tentando di accedere alla risorsa, devi dargli il percorso relativo che inizia con '/'. La strategia consigliata consiste nell'inserire i file di risorse in una cartella "risorse" nella directory principale. Quindi ad esempio se hai la struttura:

src/main/com/mycompany/myapp

quindi puoi aggiungere una cartella delle risorse come consigliato da Maven in:

src/main/resources

inoltre è possibile aggiungere sottocartelle nella cartella delle risorse

src/main/resources/textfiles

e dì che il tuo file si chiama myfile.txtcosì hai

src/main/resources/textfiles/myfile.txt

Ora è qui che entra in gioco lo stupido problema del percorso. Supponi di avere una classe nella tua com.mycompany.myapp packagee di voler accedere al myfile.txtfile dalla cartella delle risorse. Alcuni dicono che devi dare il:

"/main/resources/textfiles/myfile.txt" path

o

"/resources/textfiles/myfile.txt"

entrambi questi sono sbagliati. Dopo aver eseguito mvn clean compile, i file e le cartelle vengono copiati in:

myapp/target/classes 

cartella. Ma la cartella delle risorse non è lì, solo le cartelle nella cartella delle risorse. Quindi hai:

myapp/target/classes/textfiles/myfile.txt

myapp/target/classes/com/mycompany/myapp/*

quindi il percorso corretto da dare al getClass().getResource("")metodo è:

"/textfiles/myfile.txt"

Ecco qui:

getClass().getResource("/textfiles/myfile.txt")

Questo non restituirà più null, ma restituirà la tua classe. Spero che questo aiuti qualcuno. È strano per me, che la "resources"cartella non venga copiata anche, ma solo le sottocartelle ei file direttamente nella "resources"cartella. Mi sembrerebbe logico che la "resources"cartella si trovasse anche sotto"myapp/target/classes"


1
Nel mio target/classes, posso vedere solo i file sotto le risorse principali e non le risorse di test. Perché?
Ava

@Ava Aggiungi la cartella di prova come cartella di origine e sei a posto!
Aakash Parashar

@Ava, certo che è tardi la risposta per te, ma potrebbe aiutare qualcuno. È necessario eseguire il mvn clean test-compilecomando, come segue compilenel ciclo di vita di Maven . Questo genererà target/test-classes.
Alexander Radchenko

35

Nella speranza di fornire ulteriori informazioni per coloro che non lo raccolgono rapidamente come gli altri, vorrei fornire il mio scenario in quanto ha una configurazione leggermente diversa. Il mio progetto è stato impostato con la seguente struttura di directory (utilizzando Eclipse):

Progetto/
  src / // codice sorgente dell'applicazione
    org /
      il mio progetto/
        MyClass.java
  test / // unit test
  res / // risorse
    images / // Immagini PNG per icone
      my-image.png
    xml / // File XSD per la convalida dei file XML con JAXB
      my-schema.xsd
    conf / // file .conf predefinito per Log4j
      log4j.conf
  librerie lib / // aggiunte al percorso di compilazione tramite le impostazioni del progetto

Ho avuto problemi a caricare le mie risorse dalla directory res . Volevo che tutte le mie risorse fossero separate dal mio codice sorgente (semplicemente per scopi di gestione / organizzazione). Quindi, quello che dovevo fare era aggiungere la directory res al build-path e quindi accedere alla risorsa tramite:

static final ClassLoader loader = MyClass.class.getClassLoader();

// in some function
loader.getResource("images/my-image.png");
loader.getResource("xml/my-schema.xsd");
loader.getResource("conf/log4j.conf");

NOTA: Il /è omesso a partire dall'inizio della stringa di risorsa perché sto usando ClassLoader.getResource (stringa) al posto di Class.getResource (String) .


1
. + 1 per aver suggerito ClassLoader
pyb

1
La migliore risposta su questo argomento! Il suggerimento di non utilizzare /all'inizio di un percorso di risorse era fondamentale!
Kayhadrin

10

Quando usi 'getResource' su una classe, un percorso relativo viene risolto in base al pacchetto in cui si trova la classe. Quando usi 'getResource' su un ClassLoader, un percorso relativo viene risolto in base alla cartella principale.

Se utilizzi un percorso assoluto, entrambi i metodi "getResource" verranno avviati dalla cartella principale.


Non dimenticare gli effetti di/
Gilberto

@nbeyer Perché l'utilizzo getResourcecon percorso assoluto inizia dalla cartella principale? Lo scopo del percorso assoluto non è assoluto ?
atjua

10

@GianCarlo: puoi provare a chiamare la proprietà di sistema user.dir che ti darà la radice del tuo progetto java e quindi aggiungere questo percorso al tuo percorso relativo, ad esempio:

String root = System.getProperty("user.dir");
String filepath = "/path/to/yourfile.txt"; // in case of Windows: "\\path \\to\\yourfile.txt
String abspath = root+filepath;



// using above path read your file into byte []
File file = new File(abspath);
FileInputStream fis = new FileInputStream(file);
byte []filebytes = new byte[(int)file.length()];
fis.read(filebytes);

1
OP voleva individuare una risorsa nel classpath (molto probabilmente in un jar generato durante la build). Questo metodo non fornisce un modo per raggiungere tale obiettivo: non è possibile puntare Filea una risorsa all'interno di un file jar, ma solo a una voce corretta nel file system (ad esempio, il jar stesso).
Attila

Mi piace l'idea di far vedere a "user.dir" il percorso desiderato. Grazie
YouAreAwesome

5

Per coloro che usano eclipse + maven. Supponi di provare ad accedere al file images/pic.jpgin src/main/resources. In questo modo:

ClassLoader loader = MyClass.class.getClassLoader();
File file = new File(loader.getResource("images/pic.jpg").getFile());

è perfettamente corretto, ma può provocare un'eccezione di puntatore nullo. Sembra che eclipse non riconosca subito le cartelle nella struttura di directory di Maven come cartelle di origine. Rimuovendo e la src/main/resourcescartella dall'elenco delle cartelle di origine del progetto e rimettendola (progetto> proprietà> percorso build java> origine> rimuovi / aggiungi cartella), sono stato in grado di risolvere questo problema.


2
resourcesloader.class.getClass()

Può essere suddiviso in:

Class<resourcesloader> clazz = resourceloader.class;
Class<Class> classClass = clazz.getClass();

Il che significa che stai cercando di caricare la risorsa usando una classe bootstrap.

Invece probabilmente vuoi qualcosa del tipo:

resourcesloader.class.getResource("repository/SSL-Key/cert.jks").toString()

Se solo javac avvertisse della chiamata di metodi statici su contesti non statici ...


1

Fai il seguente lavoro?

resourcesloader.class.getClass().getResource("/package1/resources/repository/SSL-Key/cert.jks")

C'è un motivo per cui non è possibile specificare il percorso completo incluso il pacchetto?


1

Andando con le due risposte come menzionato sopra. Il primo

resourcesloader.class.getClassLoader().getResource("package1/resources/repository/SSL-Key/cert.jks").toString();
resourcesloader.class.getResource("repository/SSL-Key/cert.jks").toString()

Dovrebbe essere la stessa cosa?


1

Per ottenere il percorso reale del file puoi provare questo:

URL fileUrl = Resourceloader.class.getResource("resources/repository/SSL-Key/cert.jks");
String pathToClass = fileUrl.getPath;    

Resourceloader è classname qui. "resources / repository / SSL-Key / cert.jks" è il percorso relativo del file. Se avessi la tua guiclass in ./package1/java con il resto della struttura delle cartelle rimanente, prenderesti "../resources/repository/SSL-Key/cert.jks" come percorso relativo a causa delle regole che definiscono il percorso relativo.

In questo modo puoi leggere il tuo file con BufferedReader. NON USARE LA STRINGA per identificare il percorso del file, perché se nel percorso sono presenti spazi o caratteri di alfabeto non inglese, si verificheranno problemi e il file non verrà trovato.

BufferedReader bufferedReader = new BufferedReader(
                        new InputStreamReader(fileUrl.openStream()));

0

Ho apportato una piccola modifica all'unica riga di @ jonathan.cone (aggiungendo .getFile()) per evitare l'eccezione del puntatore nullo e impostando il percorso della directory dei dati. Ecco cosa ha funzionato per me:

String realmID = new java.util.Scanner(new java.io.File(RandomDataGenerator.class.getClassLoader().getResource("data/aa-qa-id.csv").getFile().toString())).next();

0

Usa questo:

resourcesloader.class.getClassLoader().getResource("/path/to/file").**getPath();**
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.