offene Ressource mit relativem Pfad in Java

82

In meiner Java-App muss ich einige Dateien und Verzeichnisse erhalten.

Dies ist die Programmstruktur:

./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 Lädt die Resourcesloader-Klasse, die meine Ressourcen (Verzeichnis und Datei) lädt.

In Bezug auf die Datei habe ich versucht

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

um den wirklichen Weg zu bekommen, aber dieser Weg funktioniert nicht.

Ich habe keine Ahnung, wie das Verzeichnis zu tun ist.

Giancarlo
quelle
1
class.getClass () ist nicht dasselbe wie class.getClassLoader (). Es gibt auch eine andere Lösung: getResourceAsStream (), die eine Klasse im selben Paket wie Ihre Ressource verwendet. Für weitere Informationen: tshikatshikaaa.blogspot.nl/2012/07/… .
Jérôme Verstrynge

Antworten:

47

Geben Sie den Pfad relativ zum Klassenlader an, nicht die Klasse, von der Sie den Lader erhalten. Zum Beispiel:

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

Ich hatte Probleme mit der getClass().getResource("filename.txt")Methode. Wenn sich Ihre Ressource beim Lesen der Java-Dokumentanweisungen nicht im selben Paket befindet wie die Klasse, von der aus Sie auf die Ressource zugreifen möchten, müssen Sie ihr einen relativen Pfad geben, beginnend mit '/'. Die empfohlene Strategie besteht darin, Ihre Ressourcendateien in einem Ordner "resources" im Stammverzeichnis abzulegen. Also zum Beispiel, wenn Sie die Struktur haben:

src/main/com/mycompany/myapp

Anschließend können Sie einen Ressourcenordner hinzufügen, wie von maven empfohlen in:

src/main/resources

Außerdem können Sie Unterordner zum Ressourcenordner hinzufügen

src/main/resources/textfiles

und sagen Sie, dass Ihre Datei aufgerufen wird, myfile.txtdamit Sie haben

src/main/resources/textfiles/myfile.txt

Hier kommt nun das dumme Pfadproblem ins Spiel. Angenommen, Sie haben eine Klasse in Ihrem com.mycompany.myapp packageund möchten myfile.txtvon Ihrem Ressourcenordner aus auf die Datei zugreifen . Einige sagen, Sie müssen geben:

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

oder

"/resources/textfiles/myfile.txt"

beide sind falsch. Nach mvn clean compiledem Ausführen werden die Dateien und Ordner in folgende Dateien kopiert:

myapp/target/classes 

Ordner. Der Ressourcenordner ist jedoch nicht vorhanden, sondern nur die Ordner im Ressourcenordner. Also hast du:

myapp/target/classes/textfiles/myfile.txt

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

Der richtige Pfad für die getClass().getResource("")Methode lautet also:

"/textfiles/myfile.txt"

hier ist es:

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

Dies gibt nicht mehr null zurück, sondern Ihre Klasse. Ich hoffe das hilft jemandem. Es ist seltsam für mich, dass der "resources"Ordner nicht ebenfalls kopiert wird, sondern nur die Unterordner und Dateien direkt im "resources"Ordner. Es erscheint mir logisch, dass sich der "resources"Ordner auch unter befindet"myapp/target/classes"

Johnny
quelle
1
In meinem target/classesFall kann ich nur Dateien unter Hauptressourcen sehen und keine Ressourcen testen. Warum?
Ava
@Ava Testordner als Quellordner hinzufügen und los geht's!
Aakash Parashar
@Ava, sicher ist es eine späte Antwort für dich, kann aber jemandem helfen. Sie müssen den mvn clean test-compileBefehl ausführen , wie er compileim Maven-Lebenszyklus ausgeführt wird . Das wird erzeugen target/test-classes.
Alexander Radchenko
33

In der Hoffnung, zusätzliche Informationen für diejenigen bereitzustellen, die dies nicht so schnell wie andere aufgreifen, möchte ich mein Szenario bereitstellen, da es ein etwas anderes Setup hat. Mein Projekt wurde mit der folgenden Verzeichnisstruktur (mit Eclipse) eingerichtet:

Projekt/
  src / // Anwendungsquellcode
    org /
      Mein Projekt/
        MyClass.java
  test / // Unit-Tests
  res / // Ressourcen
    images / // PNG-Bilder für Symbole
      my-image.png
    xml / // XSD-Dateien zum Überprüfen von XML-Dateien mit JAXB
      my-schema.xsd
    conf / // Standard-.conf-Datei für Log4j
      log4j.conf
  lib / // Bibliotheken, die über Projekteinstellungen zum Build-Pfad hinzugefügt wurden

Ich hatte Probleme beim Laden meiner Ressourcen aus dem res- Verzeichnis. Ich wollte alle meine Ressourcen von meinem Quellcode trennen (einfach zu Verwaltungs- / Organisationszwecken). Also musste ich das res- Verzeichnis zum Build-Pfad hinzufügen und dann auf die Ressource zugreifen über:

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");

HINWEIS: Das /wird am Anfang der Ressourcenzeichenfolge weggelassen, da ich ClassLoader.getResource (String) anstelle von Class.getResource (String) verwende .

E-reich
quelle
1
. + 1 für den Vorschlag von ClassLoader
pyb
1
Beste Antwort zu diesem Thema! Der Tipp, /am Anfang eines Ressourcenpfads nicht zu verwenden, war der Schlüssel!
Kayhadrin
10

@GianCarlo: Sie können versuchen, die Systemeigenschaft user.dir aufzurufen, die Ihnen das Stammverzeichnis Ihres Java-Projekts gibt, und diesen Pfad dann an Ihren relativen Pfad anhängen, zum Beispiel:

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);
Vikram
quelle
1
OP wollte eine Ressource im Klassenpfad finden (höchstwahrscheinlich in einem JAR, das während des Builds generiert wurde). Diese Methode bietet keine Möglichkeit, dieses Ziel zu erreichen. Sie können nicht Fileauf eine Ressource in einer JAR-Datei verweisen, sondern nur auf einen ordnungsgemäßen Eintrag im Dateisystem (z. B. das JAR selbst).
Attila
Ich mag die Idee, "user.dir" dazu zu bringen, den gewünschten Pfad zu sehen. Vielen Dank
YouAreAwesome
9

Wenn Sie 'getResource' für eine Klasse verwenden, wird ein relativer Pfad basierend auf dem Paket aufgelöst, in dem sich die Klasse befindet. Wenn Sie 'getResource' für einen ClassLoader verwenden, wird ein relativer Pfad basierend auf dem Stammordner aufgelöst.

Wenn Sie einen absoluten Pfad verwenden, beginnen beide 'getResource'-Methoden im Stammordner.

nbeyer
quelle
Vergessen Sie nicht die Auswirkungen von/
Gilberto
@nbeyer Warum beginnt die Verwendung getResourcemit absolutem Pfad im Stammordner? Ist der Zweck des absoluten Pfades nicht absolut ?
Atjua
5

Für diejenigen, die Eclipse + Maven verwenden. Angenommen, Sie versuchen, auf die Datei images/pic.jpgin zuzugreifen src/main/resources. So geht's:

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

ist vollkommen korrekt, kann jedoch zu einer Nullzeigerausnahme führen. Eclipse erkennt die Ordner in der Maven-Verzeichnisstruktur anscheinend nicht sofort als Quellordner. Durch Entfernen und src/main/resourcesZurücksetzen des Ordners aus der Quellordnerliste des Projekts (Projekt> Eigenschaften> Java-Erstellungspfad> Quelle> Ordner entfernen / hinzufügen) konnte ich dieses Problem lösen.

Paul Mira
quelle
2
resourcesloader.class.getClass()

Kann unterteilt werden in:

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

Dies bedeutet, dass Sie versuchen, die Ressource mithilfe einer Bootstrap-Klasse zu laden.

Stattdessen möchten Sie wahrscheinlich etwas wie:

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

Wenn nur javac davor warnt, statische Methoden in nicht statischen Kontexten aufzurufen ...

Tom Hawtin - Tackline
quelle
1

Machst du folgende Arbeit?

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

Gibt es einen Grund, warum Sie nicht den vollständigen Pfad einschließlich des Pakets angeben können?

RichH
quelle
1

Gehen Sie mit den beiden Antworten wie oben erwähnt. Der erste

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

Sollte ein und dasselbe sein?

manocha_ak
quelle
1

Um einen echten Pfad zur Datei zu erhalten, können Sie Folgendes versuchen:

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

Resourceloader ist hier Klassenname. "resources / repository / SSL-Key / cert.jks" ist der relative Pfad zur Datei. Wenn Sie Ihre Guiclass in ./package1/java mit verbleibender Restordnerstruktur hätten, würden Sie "../resources/repository/SSL-Key/cert.jks" als relativen Pfad verwenden, da Regeln den relativen Pfad definieren.

Auf diese Weise können Sie Ihre Datei mit BufferedReader lesen. Verwenden Sie die Zeichenfolge NICHT, um den Pfad zur Datei zu identifizieren. Wenn Sie Leerzeichen oder Zeichen aus einem nicht englischen Alphabet in Ihrem Pfad haben, treten Probleme auf und die Datei wird nicht gefunden.

BufferedReader bufferedReader = new BufferedReader(
                        new InputStreamReader(fileUrl.openStream()));
Nikto
quelle
0

Ich habe eine kleine Änderung am Einzeiler von @ jonathan.cone vorgenommen (durch Hinzufügen .getFile()), um eine Nullzeigerausnahme zu vermeiden und den Pfad zum Datenverzeichnis festzulegen . Folgendes hat bei mir funktioniert:

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

Benutze das:

resourcesloader.class.getClassLoader().getResource("/path/to/file").**getPath();**
Oleg Poltoratskii
quelle