Dienstprogramme zum Lesen der Ressourcentextdatei in String (Java) [geschlossen]
215
Gibt es ein Dienstprogramm, mit dem eine Textdatei in der Ressource in einen String eingelesen werden kann? Ich nehme an, dies ist eine beliebte Anforderung, aber ich konnte nach dem Googeln kein Dienstprogramm finden.
Bitte klären Sie, was Sie unter "Ressourcentextdatei" und "Textdatei in Ressource" verstehen. Es ist nicht leicht zu verstehen, was Sie erreichen möchten.
Mat
Das ist nur eine Textdatei unter Klassenpfad wie "Klassenpfad *: mytext / text.txt"
Loc Phan
Antworten:
301
Ja, Guava bietet dies in der ResourcesKlasse an. Beispielsweise:
URL url =Resources.getResource("foo.txt");String text =Resources.toString(url,StandardCharsets.UTF_8);
@JonSkeet Dies ist großartig, aber für Webanwendungen ist es möglicherweise nicht die beste Lösung, die Implementierung von getResourcewird verwendet, Resource.class.getClassLoaderaber in Webanwendungen ist dies möglicherweise nicht "Ihr" Klassenladeprogramm, daher wird die Verwendung empfohlen (z. B. in [1]) Thread.currentThread().getContextClassLoader().getResourceAsStreamstattdessen (Referenz [1]: stackoverflow.com/questions/676250/… )
Eran Medan
2
@EranMedan: Ja, wenn Sie den Kontextklassenlader möchten, möchten Sie ihn explizit verwenden.
Jon Skeet
6
In dem speziellen Fall, in dem sich die Ressource neben Ihrer Klasse befindet, können Sie dies tun Resources.toString(MyClass.getResource("foo.txt"), Charsets.UTF_8), um die Verwendung des richtigen Klassenladeprogramms zu gewährleisten.
Bogdan Calmac
2
com.google.common.io.Resourcesist laut SonarQube
Ghilteras
1
guavahat die Implementierung geändert. Für Guave 23 mag die Implementierung Folgendes. ClassLoader loader = MoreObjects.firstNonNull( Thread.currentThread().getContextClassLoader(), Resources.class.getClassLoader());
xxy
170
Sie können den alten Stupid Scanner Trick Oneliner verwenden, um dies ohne zusätzliche Abhängigkeit wie Guave zu tun:
String text =newScanner(AppropriateClass.class.getResourceAsStream("foo.txt"),"UTF-8").useDelimiter("\\A").next();
Leute, benutzt keine Sachen von Drittanbietern, es sei denn, ihr braucht das wirklich. Das JDK bietet bereits viele Funktionen.
Das Vermeiden von Dritten ist ein vernünftiger Grundsatz. Leider scheint die Kernbibliothek allergisch gegen die Modellierung realer Anwendungsfälle zu sein. Schauen Sie sich die Dateien von Java 7 an und sagen Sie mir, warum das Lesen von allem aus einer Klassenpfadressource dort nicht enthalten war. Oder zumindest mit einem standardisierten "Dateisystem".
Dilum Ranatunga
3
Ist es notwendig oder nicht, den Stream ebenfalls zu schließen? Guave schließt den Stream intern.
Jungfrau47
Hat auch bei mir wunderbar funktioniert! Ich stimme auch der Sache mit Drittanbietern zu: Bei vielen Antworten scheint die Standardantwort immer darin zu bestehen, eine Bibliothek von Drittanbietern zu verwenden - sei es von Apache oder von jemand anderem.
Terje Dahl
1
Wechseln Sie CartApplication.class.getResourceAsStreamzu CartApplication.class.getClassLoader().getResourceAsStream, um Ressourcen in das aktuelle Glas zu laden. Wie srm / test / resources
Chris DaMour
5
Während ich dies verwendet habe, bin ich völlig anderer Meinung, wenn es darum geht, Pakete von Drittanbietern zu vermeiden. Die Tatsache, dass in Java die einzige Möglichkeit, eine Datei einfach in einen String zu lesen, der Scannertrick ist, ist ziemlich traurig. Die Alternative zur Verwendung einer Drittanbieter-Bibliothek besteht darin, dass jeder nur seine eigenen Wrapper erstellt. Guava for IO gewinnt zweifellos, wenn Sie viele Anforderungen für diese Art von Operation haben. Ich werde zustimmen, dass Sie kein Paket eines Drittanbieters importieren sollten, wenn Sie nur eine Stelle in Ihrem Code haben, an der Sie dies tun möchten. Das wäre übertrieben imo.
Erklären Sie bitte, warum dies funktioniert, warum es besser ist als andere Alternativen und welche Leistungs- / Codierungsüberlegungen erforderlich sind.
Nanofarad
5
Es ist nio 2 in Java 1.7. Es ist einheimische Feture von Java. Verwenden Sie für die Codierung einen neuen String (Bytes, StandardCharsets.UTF_8)
Kovalsky Dmitryi
5
in meinem Fall brauchte ich getClass().getClassLoader()aber sonst tolle Lösung!
Emmanuel Touzery
3
Dies wird nicht funktionieren, sobald die App in ein Glas gepackt ist.
Daniel Bo
65
Reine und einfache, jar-freundliche Java 8+ -Lösung
Diese einfache Methode reicht aus, wenn Sie Java 8 oder höher verwenden:
/**
* Reads given resource file as a string.
*
* @param fileName path to the resource file
* @return the file's contents
* @throws IOException if read fails for any reason
*/staticString getResourceFileAsString(String fileName)throwsIOException{ClassLoader classLoader =ClassLoader.getSystemClassLoader();try(InputStream is = classLoader.getResourceAsStream(fileName)){if(is ==null)returnnull;try(InputStreamReader isr =newInputStreamReader(is);BufferedReader reader =newBufferedReader(isr)){return reader.lines().collect(Collectors.joining(System.lineSeparator()));}}}
Und es funktioniert auch mit Ressourcen in JAR-Dateien .
Informationen zur Textcodierung: InputStreamReaderVerwendet den Standard-Systemzeichensatz, falls Sie keinen angeben. Sie können es selbst angeben, um Dekodierungsprobleme wie folgt zu vermeiden:
newInputStreamReader(isr,StandardCharsets.UTF_8);
Vermeiden Sie unnötige Abhängigkeiten
Immer lieber nicht abhängig von großen, fetten Bibliotheken. Sofern Sie Guava oder Apache Commons IO nicht bereits für andere Aufgaben verwenden, erscheint es etwas zu viel, diese Bibliotheken zu Ihrem Projekt hinzuzufügen, nur um aus einer Datei lesen zu können.
"Einfache" Methode? Du machst wohl Witze
Ich verstehe, dass reines Java keine gute Arbeit leistet, wenn es darum geht, einfache Aufgaben wie diese zu erledigen. So lesen wir zum Beispiel aus einer Datei in Node.js:
Einfach und leicht zu lesen (obwohl sich die Leute sowieso immer noch gerne auf viele Abhängigkeiten verlassen, hauptsächlich aus Unwissenheit). Oder in Python:
with open('some-file.txt','r')as f:
content = f.read()
Es ist traurig, aber für Javas Standards immer noch einfach. Sie müssen lediglich die oben beschriebene Methode in Ihr Projekt kopieren und verwenden. Ich bitte Sie nicht einmal zu verstehen, was dort vor sich geht, weil es für niemanden wirklich wichtig ist. Es funktioniert einfach, Punkt :-)
@zakmck bitte versuchen Sie Ihre Kommentare konstruktiv zu halten. Wenn Sie als reifer Entwickler aufwachsen, lernen Sie, dass Sie manchmal das Rad neu erfinden möchten. Beispielsweise müssen Sie Ihre Binärdatei möglicherweise unter einem bestimmten Schwellenwert halten. Durch Bibliotheken wächst Ihre Anwendungsgröße häufig um Größenordnungen. Man könnte genau das Gegenteil von dem argumentieren, was Sie gesagt haben: "Sie müssen keinen Code schreiben. Ja, importieren wir einfach jedes Mal Bibliotheken." Möchten Sie wirklich lieber eine Bibliothek importieren, um 3 Codezeilen zu sparen? Ich wette, dass das Hinzufügen der Bibliothek Ihren LOC um mehr als das erhöht. Der Schlüssel ist das Gleichgewicht.
Lucio Paiva
3
Nun, nicht jeder führt Sachen in der Cloud aus. Es gibt überall eingebettete Systeme, auf denen beispielsweise Java ausgeführt wird. Ich sehe Ihren Sinn einfach nicht darin, Antworten zu kritisieren, die absolut gültige Ansätze bieten, da Sie sich selbst erwähnen, dass Sie den Vorschlag akzeptieren werden, JDK direkt in Ihrem eigenen Code zu verwenden. Wie auch immer, versuchen wir bitte, die Kommentare streng zu halten, um die Antworten zu verbessern, und nicht um Meinungen zu diskutieren.
Lucio Paiva
1
Gute JDK-Lösung. Ich würde nur prüfen, ob InputStreamVariable isist nulloder nicht.
Auditari
2
Nett. Ich habe das benutzt. Sie können auch die Streams / Reader schließen.
Dimplex
1
@RobertBain Ich habe die Antwort bearbeitet, um Informationen zur Zeichensatzwarnung hinzuzufügen. Lassen Sie mich wissen, wenn Sie herausfinden, was mit dem Klassenladeprogramm in AWS schief gelaufen ist, damit ich es auch der Antwort hinzufügen kann. Vielen Dank!
Lucio Paiva
57
Guava hat eine "toString" -Methode zum Einlesen einer Datei in einen String:
Oder wenn es sich um einen Eingabestream handelt, hat Guave auch dafür einen guten WegString stringFromStream = CharStreams.toString(new InputStreamReader(resourceAsStream, "UTF-8"));
Ich bevorzuge "" für den Fall, dass dies nicht verfügbar ist
user833970
11
Genauso kompakt, aber mit dem richtigen Schließen des Eingabestreams : IOUtils.toString(this.getClass().getResource("foo.xml"), "UTF-8").
Bogdan Calmac
1
Wenn diese Lösung nicht funktioniert, fügen Sie getClassLoader()der Methodenkette String text = IOUtils.toString( getClass().getClassLoader().getResourceAsStream("foo.xml"), StandardCharsets.UTF_8);
URL url =Resources.getResource("myFile.txt");File myFile =newFile(url.toURI());String content =FileUtils.readFileToString(myFile,"UTF-8");// or any other encoding
Warum muss man die Kodierung angeben, das verstehe ich nicht. Wenn ich die Datei lese, möchte ich nur, was darin enthalten ist. Sie sollte herausfinden, wie die Codierung meines Editors funktioniert. Wenn ich in Notepad oder ++ öffne, sage ich nicht, welche Codierung verwendet werden soll. Ich benutze diese Methode und schreibe danachStringToFile ... aber der Inhalt unterscheidet sich. Ich bekomme seltsame Token in der geklonten Datei. Ich verstehe nicht, warum ich eine Codierung angeben muss.
mmm
11
@Hamidan, die Auswahl der richtigen Codierung ist ein sehr komplexer Algorithmus. Es wird häufig im Texteditor implementiert, aber manchmal wird die richtige Codierung nicht erkannt. Ich würde nicht erwarten, dass eine API zum Lesen von Dateien einen so komplexen Algorithmus zum Lesen meiner Datei einbettet.
Vincent Robert
1
@SecretService Außerdem verwenden diese Algorithmen Informationen wie die Sprache, das Gebietsschema und andere regionale Einstellungen des Betriebssystems. Dies bedeutet, dass das Lesen einer Datei ohne Angabe einer Codierung möglicherweise in Ihrem Setup funktioniert, nicht jedoch in der eines anderen.
Ich denke nicht, dass dies funktionieren wird, wenn sich die Ressource in einem Glas befindet. Dann wird es keine Datei sein.
Ville Oikarinen
16
Ich hatte dieses Problem oft selbst. Um Abhängigkeiten von kleinen Projekten zu vermeiden, schreibe ich oft eine kleine Dienstprogrammfunktion, wenn ich kein Commons io oder ähnliches benötige. Hier ist der Code zum Laden des Inhalts der Datei in einen Zeichenfolgenpuffer:
StringBuffer sb =newStringBuffer();BufferedReader br =newBufferedReader(newInputStreamReader(getClass().getResourceAsStream("path/to/textfile.txt"),"UTF-8"));for(int c = br.read(); c !=-1; c = br.read()) sb.append((char)c);System.out.println(sb.toString());
In diesem Fall ist es wichtig, die Codierung anzugeben , da Sie Ihre Datei möglicherweise in UTF-8 bearbeitet und dann in eine JAR-Datei gestellt haben und der Computer, der die Datei öffnet, möglicherweise CP-1251 als native Dateicodierung hat (z. B.). ;; In diesem Fall kennen Sie die Zielcodierung nie. Daher sind die expliziten Codierungsinformationen von entscheidender Bedeutung. Auch die Schleife zum Lesen der Datei char by char scheint ineffizient zu sein, wird aber auf einem BufferedReader verwendet und ist daher eigentlich recht schnell.
Welche Importanweisungen werden benötigt, um die Klassen "Dateien" und "Pfade" abzurufen?
Steve Scherer
1
Beide sind Teil des Pakets java.nio.file, das von JDK 7+
Raghu K Nair
Funktioniert nicht in einer JAR-Datei.
Displee
4
Wenn Sie Ihren String aus einer Projektressource wie der Datei testcase / foo.json in src / main / resources in Ihrem Projekt abrufen möchten, gehen Sie folgendermaßen vor:
Datei funktioniert nur für Klassenpfadressourcen, bei denen es sich um Dateien handelt. Nicht, wenn es sich um Elemente in einer JAR-Datei oder um einen Teil eines Fat Jars handelt, einer der anderen Classloader-Implementierungen.
Werkzeugschmiede
2
Ich verwende Folgendes zum Lesen von Ressourcendateien aus classpath:
package test;import java.io.InputStream;import java.nio.charset.StandardCharsets;import java.util.Scanner;publicclassMain{publicstaticvoid main(String[] args){try{String fileContent = getFileFromResources("resourcesFile.txt");System.out.println(fileContent);}catch(Exception e){
e.printStackTrace();}}//USE THIS FUNCTION TO READ CONTENT OF A FILE, IT MUST EXIST IN "RESOURCES" FOLDERpublicstaticString getFileFromResources(String fileName)throwsException{ClassLoader classLoader =Main.class.getClassLoader();InputStream stream = classLoader.getResourceAsStream(fileName);String text =null;try(Scanner scanner =newScanner(stream,StandardCharsets.UTF_8.name())){
text = scanner.useDelimiter("\\A").next();}return text;}}
Zumindest ab Apache commons-io 2.5 unterstützt die Methode IOUtils.toString () ein URI-Argument und gibt den Inhalt von Dateien zurück, die sich in Jars im Klassenpfad befinden:
Ich mag Akosickis Antwort mit dem dummen Scanner-Trick. Es ist das einfachste, das ich ohne externe Abhängigkeiten sehe, das in Java 8 funktioniert (und tatsächlich bis zurück zu Java 5). Hier ist eine noch einfachere Antwort, wenn Sie Java 9 oder höher verwenden können (da InputStream.readAllBytes()es bei Java 9 hinzugefügt wurde):
String text =newString(AppropriateClass.class.getResourceAsStream("foo.txt").readAllBytes());
Bitte lesen Sie hier , um 3 Möglichkeiten ( BufferedReadergegen Guavas Filesgegen Guavas Resources) zu vergleichen, um Stringaus einer Textdatei zu gelangen .
Woher kommen IOUtils? Die Quelle sollte eindeutig angegeben werden.
Ehecatl
0
Ich habe hier readResource () -Methoden geschrieben , um dies in einem einfachen Aufruf tun zu können. Es hängt von der Guava-Bibliothek ab, aber ich mag nur JDK-Methoden, die in anderen Antworten vorgeschlagen werden, und ich denke, ich werde diese auf diese Weise ändern.
publicclassUtils{publicstaticString readResource(String name)throwsURISyntaxException,IOException{
var uri =Utils.class.getResource("/"+ name).toURI();
var path =Paths.get(uri);returnFiles.readString(path);}}
Ich mag Apache Commons-Utils für diese Art von Dingen und verwende diesen genauen Anwendungsfall (Lesen von Dateien aus dem Klassenpfad) ausgiebig beim Testen, insbesondere zum Lesen von JSON-Dateien /src/test/resourcesim Rahmen von Unit- / Integrationstests. z.B
publicclassFileUtils{publicstaticString getResource(String classpathLocation){try{String message =IOUtils.toString(FileUtils.class.getResourceAsStream(classpathLocation),Charset.defaultCharset());return message;}catch(IOException e){thrownewRuntimeException("Could not read file [ "+ classpathLocation +" ] from classpath", e);}}}
Zu Testzwecken kann es schön sein, das zu fangen IOExceptionund ein zu werfen RuntimeException- Ihre Testklasse könnte aussehen wie z
@Testpublicvoid shouldDoSomething (){String json =FileUtils.getResource("/json/input.json");// Use json as part of test ...}
Antworten:
Ja, Guava bietet dies in der
Resources
Klasse an. Beispielsweise:quelle
getResource
wird verwendet,Resource.class.getClassLoader
aber in Webanwendungen ist dies möglicherweise nicht "Ihr" Klassenladeprogramm, daher wird die Verwendung empfohlen (z. B. in [1])Thread.currentThread().getContextClassLoader().getResourceAsStream
stattdessen (Referenz [1]: stackoverflow.com/questions/676250/… )Resources.toString(MyClass.getResource("foo.txt"), Charsets.UTF_8)
, um die Verwendung des richtigen Klassenladeprogramms zu gewährleisten.com.google.common.io.Resources
ist laut SonarQubeguava
hat die Implementierung geändert. Für Guave 23 mag die Implementierung Folgendes.ClassLoader loader = MoreObjects.firstNonNull( Thread.currentThread().getContextClassLoader(), Resources.class.getClassLoader());
Sie können den alten Stupid Scanner Trick Oneliner verwenden, um dies ohne zusätzliche Abhängigkeit wie Guave zu tun:
Leute, benutzt keine Sachen von Drittanbietern, es sei denn, ihr braucht das wirklich. Das JDK bietet bereits viele Funktionen.
quelle
CartApplication.class.getResourceAsStream
zuCartApplication.class.getClassLoader().getResourceAsStream
, um Ressourcen in das aktuelle Glas zu laden. Wie srm / test / resourcesFür Java 7:
quelle
getClass().getClassLoader()
aber sonst tolle Lösung!Reine und einfache, jar-freundliche Java 8+ -Lösung
Diese einfache Methode reicht aus, wenn Sie Java 8 oder höher verwenden:
Und es funktioniert auch mit Ressourcen in JAR-Dateien .
Informationen zur Textcodierung:
InputStreamReader
Verwendet den Standard-Systemzeichensatz, falls Sie keinen angeben. Sie können es selbst angeben, um Dekodierungsprobleme wie folgt zu vermeiden:Vermeiden Sie unnötige Abhängigkeiten
Immer lieber nicht abhängig von großen, fetten Bibliotheken. Sofern Sie Guava oder Apache Commons IO nicht bereits für andere Aufgaben verwenden, erscheint es etwas zu viel, diese Bibliotheken zu Ihrem Projekt hinzuzufügen, nur um aus einer Datei lesen zu können.
"Einfache" Methode? Du machst wohl Witze
Ich verstehe, dass reines Java keine gute Arbeit leistet, wenn es darum geht, einfache Aufgaben wie diese zu erledigen. So lesen wir zum Beispiel aus einer Datei in Node.js:
Einfach und leicht zu lesen (obwohl sich die Leute sowieso immer noch gerne auf viele Abhängigkeiten verlassen, hauptsächlich aus Unwissenheit). Oder in Python:
Es ist traurig, aber für Javas Standards immer noch einfach. Sie müssen lediglich die oben beschriebene Methode in Ihr Projekt kopieren und verwenden. Ich bitte Sie nicht einmal zu verstehen, was dort vor sich geht, weil es für niemanden wirklich wichtig ist. Es funktioniert einfach, Punkt :-)
quelle
InputStream
Variableis
istnull
oder nicht.Guava hat eine "toString" -Methode zum Einlesen einer Datei in einen String:
Für diese Methode muss sich die Datei nicht im Klassenpfad befinden (wie in der vorherigen Antwort von Jon Skeet ).
quelle
String stringFromStream = CharStreams.toString(new InputStreamReader(resourceAsStream, "UTF-8"));
yegor256 hat mit Apache Commons IO eine gute Lösung gefunden :
quelle
IOUtils.toString(this.getClass().getResource("foo.xml"), "UTF-8")
.getClassLoader()
der MethodenketteString text = IOUtils.toString( getClass().getClassLoader().getResourceAsStream("foo.xml"), StandardCharsets.UTF_8);
apache-commons-io hat einen Dienstprogrammnamen
FileUtils
:quelle
Ich hatte dieses Problem oft selbst. Um Abhängigkeiten von kleinen Projekten zu vermeiden, schreibe ich oft eine kleine Dienstprogrammfunktion, wenn ich kein Commons io oder ähnliches benötige. Hier ist der Code zum Laden des Inhalts der Datei in einen Zeichenfolgenpuffer:
In diesem Fall ist es wichtig, die Codierung anzugeben , da Sie Ihre Datei möglicherweise in UTF-8 bearbeitet und dann in eine JAR-Datei gestellt haben und der Computer, der die Datei öffnet, möglicherweise CP-1251 als native Dateicodierung hat (z. B.). ;; In diesem Fall kennen Sie die Zielcodierung nie. Daher sind die expliziten Codierungsinformationen von entscheidender Bedeutung. Auch die Schleife zum Lesen der Datei char by char scheint ineffizient zu sein, wird aber auf einem BufferedReader verwendet und ist daher eigentlich recht schnell.
quelle
Sie können das folgende Codeformular Java verwenden
quelle
Wenn Sie Ihren String aus einer Projektressource wie der Datei testcase / foo.json in src / main / resources in Ihrem Projekt abrufen möchten, gehen Sie folgendermaßen vor:
Beachten Sie, dass die Methode getClassLoader () in einigen anderen Beispielen fehlt.
quelle
Verwenden Sie die FileUtils von Apache Commons. Es hat eine Methode readFileToString
quelle
Ich verwende Folgendes zum Lesen von Ressourcendateien aus
classpath
:Keine Abhängigkeiten von Drittanbietern erforderlich.
quelle
Mit einer Reihe von statischen Importen kann die Guava-Lösung ein sehr kompakter Einzeiler sein:
Folgende Importe sind erforderlich:
quelle
quelle
Zumindest ab Apache commons-io 2.5 unterstützt die Methode IOUtils.toString () ein URI-Argument und gibt den Inhalt von Dateien zurück, die sich in Jars im Klassenpfad befinden:
quelle
Ich mag Akosickis Antwort mit dem dummen Scanner-Trick. Es ist das einfachste, das ich ohne externe Abhängigkeiten sehe, das in Java 8 funktioniert (und tatsächlich bis zurück zu Java 5). Hier ist eine noch einfachere Antwort, wenn Sie Java 9 oder höher verwenden können (da
InputStream.readAllBytes()
es bei Java 9 hinzugefügt wurde):quelle
Guave hat auch,
Files.readLines()
wenn Sie einen Rückgabewert alsList<String>
Zeile für Zeile wünschen :Bitte lesen Sie hier , um 3 Möglichkeiten (
BufferedReader
gegen GuavasFiles
gegen GuavasResources
) zu vergleichen, umString
aus einer Textdatei zu gelangen .quelle
Charsets
ist auch in Guave. Siehe dies: google.github.io/guava/releases/23.0/api/docsHier ist mein Ansatz gut funktioniert
quelle
Ich habe hier readResource () -Methoden geschrieben , um dies in einem einfachen Aufruf tun zu können. Es hängt von der Guava-Bibliothek ab, aber ich mag nur JDK-Methoden, die in anderen Antworten vorgeschlagen werden, und ich denke, ich werde diese auf diese Weise ändern.
quelle
Wenn Sie Guava einschließen, können Sie Folgendes verwenden:
(Andere Lösungen erwähnten andere Methoden für Guave, aber sie sind veraltet)
quelle
Die folgenden Cods funktionieren für mich:
quelle
Hier ist eine Lösung mit Java 11
Files.readString
:quelle
Ich habe eine statische Methode ohne Abhängigkeit wie folgt erstellt:
quelle
Ich mag Apache Commons-Utils für diese Art von Dingen und verwende diesen genauen Anwendungsfall (Lesen von Dateien aus dem Klassenpfad) ausgiebig beim Testen, insbesondere zum Lesen von JSON-Dateien
/src/test/resources
im Rahmen von Unit- / Integrationstests. z.BZu Testzwecken kann es schön sein, das zu fangen
IOException
und ein zu werfenRuntimeException
- Ihre Testklasse könnte aussehen wie zquelle
quelle