it-swarm.com.de

getResourceAsStream gibt null zurück

Ich lade eine Textdatei aus einem Paket in einem kompilierten JAR meines Java-Projekts. Die relevante Verzeichnisstruktur sieht wie folgt aus:

/src/initialization/Lifepaths.txt

Der zum Laden der Datei verwendete Code lautet:

public class Lifepaths {
    public static void execute() {
        System.out.println(Lifepaths.class.getClass().
            getResourceAsStream("/initialization/Lifepaths.txt"));
    }

    private Lifepaths() {}

    //This is temporary; will eventually be called from outside
    public static void main(String[] args) {execute();}
}

Der Ausdruck wird immer null gedruckt, egal was ich verwende. Ich bin mir nicht sicher, warum das oben nicht funktionieren würde, also habe ich es auch versucht:

  • "/src/initialization/Lifepaths.txt"
  • "initialization/Lifepaths.txt"
  • "Lifepaths.txt"

Keine dieser Arbeiten. Ich habegelesenzahlreicheFragen bis jetzt zum Thema, aber keiner von ihnen war hilfreich - normalerweise sagen sie nur, dass Dateien über den Root-Pfad geladen werden sollen Mache ich schon Das oder laden Sie einfach die Datei aus dem aktuellen Verzeichnis (laden Sie einfach filename), was ich auch probiert habe. Die Datei wird an der entsprechenden Stelle mit dem entsprechenden Namen in die JAR-Datei kompiliert. 

Wie löse ich das?

135
Zyerah

Lifepaths.class.getClass().getResourceAsStream(...) lädt Ressourcen mithilfe des Systemklassenladers. Dies schlägt offensichtlich fehl, da Ihre JARs nicht angezeigt werden

Lifepaths.class.getResourceAsStream(...) lädt Ressourcen mit demselben Klassenlader, der die Lifepaths-Klasse geladen hat, und sollte Zugriff auf Ressourcen in Ihren JARs haben

125
hoaz

Die Regeln lauten wie folgt:

  1. Überprüfen Sie den Speicherort der Datei, die Sie in das JAR laden möchten (und stellen Sie sicher, dass sie tatsächlich zum JAR hinzugefügt wird).
  2. verwenden Sie einen absoluten Pfad: Der Pfad beginnt am Stamm der JAR
  3. verwenden Sie einen relativen Pfad: Pfad beginnt im Paketverzeichnis der Klasse, die Sie getResource/getResoucreAsStream aufrufen

Und versuche:

Lifepaths.class.getResourceAsStream("/initialization/Lifepaths.txt")

anstatt

Lifepaths.class.getClass().getResourceAsStream("/initialization/Lifepaths.txt")

(Nicht sicher, ob es einen Unterschied macht, aber der erste wird den korrekten ClassLoader/JAR verwenden, während ich bei letzterem nicht sicher bin.)

50
Puce

Es gibt also mehrere Möglichkeiten, eine Ressource aus einer JAR-Datei abzurufen, und jede hat eine leicht unterschiedliche Syntax, bei der der Pfad unterschiedlich angegeben werden muss.

Die beste Erklärung, die ich gesehen habe, ist dieser Artikel aus JavaWorld . Ich werde es hier zusammenfassen, aber wenn Sie mehr wissen wollen, sollten Sie den Artikel lesen.

Methoden

1) ClassLoader.getResourceAsStream().

Format: "/" - getrennte Namen; Kein führendes "/" (alle Namen sind absolut).

Beispiel: this.getClass().getClassLoader().getResourceAsStream("some/pkg/resource.properties");

2) Class.getResourceAsStream()

Format: "/" - getrennte Namen; führendes "/" kennzeichnet absolute Namen; Alle anderen Namen beziehen sich auf das Paket der Klasse

Beispiel: this.getClass().getResourceAsStream("/some/pkg/resource.properties");

42
greedybuddha

Verwenden Sie keine absoluten Pfade, sondern machen Sie sie relativ zum 'resources'-Verzeichnis in Ihrem Projekt. Schneller und fehlerhafter Code, der den Inhalt von MyTest.txt aus dem Verzeichnis 'resources' anzeigt.

@Test
public void testDefaultResource() {
    // can we see default resources
    BufferedInputStream result = (BufferedInputStream) 
         Config.class.getClassLoader().getResourceAsStream("MyTest.txt");
    byte [] b = new byte[256];
    int val = 0;
    String txt = null;
    do {
        try {
            val = result.read(b);
            if (val > 0) {
                txt += new String(b, 0, val);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } 
    } while (val > -1);
    System.out.println(txt);
}
12
Paul Smith

Möglicherweise möchten Sie dies versuchen, um den Stream abzurufen, d. H. Zuerst die URL und dann als Stream öffnen. 

URL url = getClass().getResource("/initialization/Lifepaths.txt"); 
InputStream strm = url.openStream(); 

Ich hatte einmal eine ähnliche Frage: Das Lesen der TXT-Datei aus dem Jar schlägt fehl, aber das Lesen des Bildes funktioniert

9
MrD

Es scheint ein Problem mit dem von Ihnen verwendeten ClassLoader zu geben. Verwenden Sie den contextClassLoader, um die Klasse zu laden. Dies ist unabhängig davon, ob es sich um eine statische/nicht statische Methode handelt

Thread.currentThread().getContextClassLoader().getResourceAsStream......

7
Binita Bharati

Ich weiß nicht, ob ich Hilfe hätte, aber in meinem Fall hatte ich meine Ressource im Ordner/src/und erhielt diese Fehlermeldung ... Ich habe das Bild in den Ordner bin verschoben und das Problem behoben.

2
Leo Ufimtsev

Stellen Sie sicher, dass sich das Ressourcenverzeichnis (z. B. "src") in Ihrem Klassenpfad befindet (stellen Sie sicher, dass es sich um ein Quellverzeichnis in Ihrem Buildpfad in Eclipse handelt).

Stellen Sie sicher, dass Clazz vom Haupt-Classloader geladen wird.

Verwenden Sie dann, um src/initialization/Lifepaths.txt zu laden 

clazz.getResourceAsStream("/initialization/Lifepaths.txt");

Warum: clazz.getResourcesAsStream(foo) sucht foo von innerhalb des Klassenpfads von clazz , relativ zu dem Verzeichnis, in dem clazz in lebt. Durch das führende "/" wird es vom Stammverzeichnis eines beliebigen Verzeichnisses im Klassenpfad von clazz geladen.

Wenn Sie sich nicht in einem Container wie Tomcat befinden oder etwas direkt mit ClassLoaders tun, können Sie Ihren Eclipse/Befehlszeilen-Klassenpfad einfach als den einzigen Klassenpfad-Klassenpfad behandeln.

2
Bobby Martin

Ich befand mich in einer ähnlichen Ausgabe. Da ich maven verwende, musste ich meine pom.xml so aktualisieren, dass sie etwa Folgendes enthält:

   ...
</dependencies>
<build>
    <resources>
        <resource>
            <directory>/src/main/resources</directory>
        </resource>
        <resource>
            <directory>../src/main/resources</directory>
        </resource>
    </resources>
    <pluginManagement>
        ...

Notieren Sie sich das Ressourcen-Tag dort, um anzugeben, wo sich der Ordner befindet. Wenn Sie (wie ich) verschachtelte Projekte haben, möchten Sie möglicherweise Ressourcen aus anderen Bereichen abrufen, anstatt nur in dem Modul, in dem Sie arbeiten. Dies verringert die Beibehaltung derselben Datei in jedem Repo, wenn Sie ähnliche Konfigurationsdaten verwenden 

1
plosco

In meinem Fall hat nichts funktioniert, wenn ich Leerzeichen aus Dateinamen entfernt habe ...

0
user3563159

Was für mich funktionierte, war, die Datei unter Mein Projekt/Java-Ressourcen/src hinzuzufügen und dann zu verwenden 

this.getClass().getClassLoader().getResourceAsStream(myfile.txt);

Ich musste diese Datei nicht explizit dem Pfad hinzufügen (das Hinzufügen von/src macht das anscheinend)

0
Pablo

Das standardmäßige JVM-Klassenladeprogramm verwendet das übergeordnete Klassenladeprogramm, um zuerst Ressourcen zu laden: deletegate-parent-classloader.

Der Klassenlader von Lifepaths.class.getClass() ist bootstrap classloader, daher durchsucht getResourceAsStream nur $ Java_HOME, unabhängig vom vom Benutzer angegebenen classpath. Offensichtlich ist Lifepaths.txt nicht da.

Der Klassenlader von Lifepaths.class ist system classpath classloader, daher sucht getResourceAsStream nach benutzerdefinierten classpath und Lifepaths.txt ist da.

Bei Verwendung von Java.lang.Class#getResourceAsStream(String name) wird ein Name, der nicht mit '/' beginnt, mit package name als Präfix hinzugefügt. Wenn Sie dies vermeiden möchten, verwenden Sie bitte Java.lang.ClassLoader#getResourceAsStream. Zum Beispiel:

ClassLoader loader = Thread.currentThread().getContextClassLoader();
String resourceName = "Lifepaths.txt";
InputStream resourceStream = loader.getResourceAsStream(resourceName); 
0
ridox