getResourceAsStream () vs FileInputStream

173

Ich habe versucht, eine Datei in eine Webanwendung zu laden, und bei der Verwendung wurde eine FileNotFoundAusnahme angezeigt FileInputStream. Unter Verwendung des gleichen Pfades konnte ich die Datei jedoch laden, als ich dies tat getResourceAsStream(). Was ist der Unterschied zwischen den beiden Methoden und warum funktioniert eine, während die andere nicht funktioniert?

Vivin Paliath
quelle

Antworten:

256

Das java.io.Fileund Konsortium wirkt auf das lokale Datenträger-Dateisystem. Die Hauptursache für Ihr Problem ist, dass die relativen Pfade in java.iovom aktuellen Arbeitsverzeichnis abhängen. Dh das Verzeichnis, von dem aus die JVM (in Ihrem Fall die des Webservers) gestartet wird. Dies kann zum Beispiel C:\Tomcat\binoder etwas ganz anderes sein, aber somit nicht C:\Tomcat\webapps\contextname oder was auch immer Sie erwarten würden. In einem normalen Eclipse-Projekt wäre das C:\Eclipse\workspace\projectname. Sie können das aktuelle Arbeitsverzeichnis folgendermaßen kennenlernen:

System.out.println(new File(".").getAbsolutePath());

Das Arbeitsverzeichnis ist jedoch in keiner Weise programmgesteuert steuerbar. Sie sollten es wirklich vorziehen, absolute Pfade in der FileAPI anstelle relativer Pfade zu verwenden. ZB C:\full\path\to\file.ext.

Sie möchten den absoluten Pfad in Java (Web) -Anwendungen nicht fest codieren oder erraten. Das ist nur ein Portabilitätsproblem (dh es läuft in System X, aber nicht in System Y). Normalerweise wird diese Art von Ressourcen in den Klassenpfad eingefügt oder der vollständige Pfad zum Klassenpfad hinzugefügt (in einer IDE wie Eclipse ist dies der srcOrdner bzw. der "Erstellungspfad"). Auf diese Weise können Sie sie mit Hilfe von ClassLoaderby ClassLoader#getResource()oder greifen ClassLoader#getResourceAsStream(). Es ist in der Lage, Dateien relativ zum "Stamm" des Klassenpfads zu finden, wie Sie zufällig herausgefunden haben. In Webanwendungen (oder jeder anderen Anwendung, die mehrere Klassenladeprogramme verwendet) wird empfohlen, die ClassLoadervon zurückgegebene Anwendung zu verwenden, Thread.currentThread().getContextClassLoader()damit Sie auch außerhalb des Webanwendungskontexts suchen können.

Eine weitere Alternative in Webapps ist das ServletContext#getResource()und sein Gegenstück ServletContext#getResourceAsStream(). Es kann auf Dateien zugreifen, die sich im öffentlichen webOrdner des Webapp-Projekts befinden, einschließlich des /WEB-INFOrdners. Das ServletContextist in Servlets durch die geerbte getServletContext()Methode verfügbar , Sie können es so wie es ist aufrufen.

Siehe auch:

BalusC
quelle
5
@ Khylo: verwandt: stackoverflow.com/questions/7952090/…
BalusC
27

getResourceAsStream ist der richtige Weg für Web-Apps (wie Sie bereits gelernt haben).

Der Grund dafür ist, dass das Lesen aus dem Dateisystem nicht funktioniert, wenn Sie Ihre Web-App in eine WAR-Datei packen. Dies ist der richtige Weg, um eine Web-App zu verpacken. Auf diese Weise ist es portabel, da Sie nicht von einem absoluten Dateipfad oder dem Speicherort Ihres App-Servers abhängig sind.

Duffymo
quelle
3
+1 - obwohl "kann nicht funktionieren" zu stark ist. (Das Lesen aus dem Dateisystem kann zum Funktionieren gebracht werden, aber es portabel zu machen ist schwierig ... und viel mehr Code, insbesondere wenn sich die Ressource in einer JAR befindet.)
Stephen C
1
duffy, sehr nette Antwort und Sie haben erklärt, was mein Fehler war, aber BalusC ging auf viele Details ein - ich denke, seine Antwort wäre hilfreich für Leute, die auch die inneren Details wissen möchten. Ich hoffe, es macht Ihnen nichts aus, wenn ich die akzeptierte Antwort auf seine ändere!
Vivin Paliath
@ Stephen - Ich denke nicht, dass "kann nicht funktionieren" zu stark ist. Selbst etwas so Einfaches wie die Bereitstellung auf zwei verschiedenen Servern mit unterschiedlichen Pfaden zum App-Server wird es beschädigen. Der Punkt ist, dass Sie Ihr WAR so eigenständig wie möglich machen müssen. Ihr Punkt ist richtig, aber ich werde mich an meinen Wortlaut halten.
Duffymo
14

FileInputStream lädt den Dateipfad, den Sie als Relativ an den Konstruktor übergeben, aus dem Arbeitsverzeichnis des Java-Prozesses. Normalerweise ist dies in einem Webcontainer so etwas wie der binOrdner.

getResourceAsStream()lädt einen Dateipfad relativ aus dem Klassenpfad Ihrer Anwendung .

matt b
quelle
12

Die FileInputStreamKlasse arbeitet direkt mit dem zugrunde liegenden Dateisystem. Wenn die betreffende Datei dort nicht physisch vorhanden ist, kann sie nicht geöffnet werden. Die getResourceAsStream()Methode funktioniert anders. Es wird versucht, die Ressource mithilfe ClassLoaderder Klasse zu finden und zu laden, für die sie aufgerufen wird. Auf diese Weise können beispielsweise in jarDateien eingebettete Ressourcen gefunden werden.

Dolch
quelle
Nun, Dateien in einem JAR sind immer noch physisch in einem Dateisystem "vorhanden", nur in anderen Dateien enthalten
matt b
1
Na ja, natürlich. In der Regel werden sie jedoch nicht als unabhängige Entitäten im Dateisystem angesehen, es sei denn, jarIhre Anwendung kennt das Dateiformat und seine Auswirkungen. Und in Java ClassLoaderkönnte der Geeignete dieses Wissen haben, während eine Ebene dies FileInputStreamsicherlich nicht hat.
Dirk
7

classname.getResourceAsStream () lädt eine Datei über den Klassenladeprogramm classname. Wenn die Klasse aus einer JAR-Datei stammt, wird dort die Ressource geladen.

Mit FileInputStream wird eine Datei aus dem Dateisystem gelesen.

Lachlan Roche
quelle
0

Ich bin hier, indem ich beide Verwendungen trenne, indem ich sie als File Read (java.io) und Resource Read (ClassLoader.getResourceAsStream ()) markiere.

Datei lesen - 1. Funktioniert auf dem lokalen Dateisystem. 2. Versucht, die aus dem aktuellen JVM-gestarteten Verzeichnis angeforderte Datei als Root zu suchen. 3. Ideal, wenn Dateien für die Verarbeitung an einem festgelegten Speicherort wie / dev / files oder C: \ Data verwendet werden.

Ressourcen lesen - 1. Arbeitet am Klassenpfad 2. Versucht, die Datei / Ressource im aktuellen oder übergeordneten Klassenladeprogramm zu finden. 3. Ideal, wenn Sie versuchen, Dateien aus gepackten Dateien wie War oder Jar zu laden.

Aditya Bhuyan
quelle