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.

Loc Phan
quelle
1
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);
Jon Skeet
quelle
21
@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 = new Scanner(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.

akosicki
quelle
41
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.
Kenny Cason
90

Für Java 7:

new String(Files.readAllBytes(Paths.get(getClass().getResource("foo.txt").toURI())));
Kovalsky Dmitryi
quelle
3
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
 */
static String getResourceFileAsString(String fileName) throws IOException {
    ClassLoader classLoader = ClassLoader.getSystemClassLoader();
    try (InputStream is = classLoader.getResourceAsStream(fileName)) {
        if (is == null) return null;
        try (InputStreamReader isr = new InputStreamReader(is);
             BufferedReader reader = new BufferedReader(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:

new InputStreamReader(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:

const fs = require("fs");
const contents = fs.readFileSync("some-file.txt", "utf-8");

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 :-)

Lucio Paiva
quelle
4
@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:

import com.google.common.base.Charsets;
import com.google.common.io.Files;

String content = Files.toString(new File("/home/x1/text.log"), Charsets.UTF_8);

Für diese Methode muss sich die Datei nicht im Klassenpfad befinden (wie in der vorherigen Antwort von Jon Skeet ).

Luciano Fiandesio
quelle
2
Oder wenn es sich um einen Eingabestream handelt, hat Guave auch dafür einen guten WegString stringFromStream = CharStreams.toString(new InputStreamReader(resourceAsStream, "UTF-8"));
Eran Medan
1
Dies ist in Guave 24.1
Andrey
47

yegor256 hat mit Apache Commons IO eine gute Lösung gefunden :

import org.apache.commons.io.IOUtils;

String text = IOUtils.toString(this.getClass().getResourceAsStream("foo.xml"),
                               "UTF-8");
Stefan Endrullis
quelle
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);
Folgendes
39

apache-commons-io hat einen Dienstprogrammnamen FileUtils:

URL url = Resources.getResource("myFile.txt");
File myFile = new File(url.toURI());

String content = FileUtils.readFileToString(myFile, "UTF-8");  // or any other encoding
Andreas Dolk
quelle
1
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.
Feuermurmel
Apache FileUtils . readLines (Datei) & copyURLToFile (URL, tempFile).
Yash
2
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 = new StringBuffer();

BufferedReader br = new BufferedReader(new InputStreamReader(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.

Harry Karadimas
quelle
15

Sie können das folgende Codeformular Java verwenden

new String(Files.readAllBytes(Paths.get(getClass().getResource("example.txt").toURI())));
Raghu K Nair
quelle
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:

String myString= 
 new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("testcase/foo.json").toURI())));

Beachten Sie, dass die Methode getClassLoader () in einigen anderen Beispielen fehlt.

Witbrock
quelle
2

Verwenden Sie die FileUtils von Apache Commons. Es hat eine Methode readFileToString

Suraj Chandran
quelle
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:

import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.Scanner;

public class ResourceUtilities
{
    public static String resourceToString(String filePath) throws IOException, URISyntaxException
    {
        try (InputStream inputStream = ResourceUtilities.class.getClassLoader().getResourceAsStream(filePath))
        {
            return inputStreamToString(inputStream);
        }
    }

    private static String inputStreamToString(InputStream inputStream)
    {
        try (Scanner scanner = new Scanner(inputStream).useDelimiter("\\A"))
        {
            return scanner.hasNext() ? scanner.next() : "";
        }
    }
}

Keine Abhängigkeiten von Drittanbietern erforderlich.

BullyWiiPlaza
quelle
1

Mit einer Reihe von statischen Importen kann die Guava-Lösung ein sehr kompakter Einzeiler sein:

toString(getResource("foo.txt"), UTF_8);

Folgende Importe sind erforderlich:

import static com.google.common.io.Resources.getResource
import static com.google.common.io.Resources.toString
import static java.nio.charset.StandardCharsets.UTF_8
Michal Kordas
quelle
1
package test;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;

public class Main {
    public static void 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" FOLDER
    public static String getFileFromResources(String fileName) throws Exception {
        ClassLoader classLoader = Main.class.getClassLoader();
        InputStream stream = classLoader.getResourceAsStream(fileName);
        String text = null;
        try (Scanner scanner = new Scanner(stream, StandardCharsets.UTF_8.name())) {
            text = scanner.useDelimiter("\\A").next();
        }
        return text;
    }
}
sklimkovitch
quelle
1

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:

IOUtils.toString(SomeClass.class.getResource(...).toURI(), ...)
user1050755
quelle
1

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 = new String(AppropriateClass.class.getResourceAsStream("foo.txt").readAllBytes());
Gary S.
quelle
0

Guave hat auch, Files.readLines()wenn Sie einen Rückgabewert als List<String>Zeile für Zeile wünschen :

List<String> lines = Files.readLines(new File("/file/path/input.txt"), Charsets.UTF_8);

Bitte lesen Sie hier , um 3 Möglichkeiten ( BufferedReadergegen Guavas Filesgegen Guavas Resources) zu vergleichen, um Stringaus einer Textdatei zu gelangen .

philipjkim
quelle
Was ist die Charsets-Klasse? ist nicht native
e-info128
@ e-info128 Charsetsist auch in Guave. Siehe dies: google.github.io/guava/releases/23.0/api/docs
philipjkim
0

Hier ist mein Ansatz gut funktioniert

public String getFileContent(String fileName) {
    String filePath = "myFolder/" + fileName+ ".json";
    try(InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath)) {
        return IOUtils.toString(stream, "UTF-8");
    } catch (IOException e) {
        // Please print your Exception
    }
}
Java_Fire_Within
quelle
2
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.

zakmck
quelle
0

Wenn Sie Guava einschließen, können Sie Folgendes verwenden:

String fileContent = Files.asCharSource(new File(filename), Charset.forName("UTF-8")).read();

(Andere Lösungen erwähnten andere Methoden für Guave, aber sie sind veraltet)

jolumg
quelle
0

Die folgenden Cods funktionieren für mich:

compile group: 'commons-io', name: 'commons-io', version: '2.6'

@Value("classpath:mockResponse.json")
private Resource mockResponse;

String mockContent = FileUtils.readFileToString(mockResponse.getFile(), "UTF-8");
Vicky
quelle
0

Hier ist eine Lösung mit Java 11 Files.readString:

public class Utils {
    public static String readResource(String name) throws URISyntaxException, IOException {
        var uri = Utils.class.getResource("/" + name).toURI();
        var path = Paths.get(uri);
        return Files.readString(path);
    }
}
Dillon Ryan Redding
quelle
0

Ich habe eine statische Methode ohne Abhängigkeit wie folgt erstellt:

import java.nio.file.Files;
import java.nio.file.Paths;

public class ResourceReader {
    public  static String asString(String resourceFIleName) {
        try  {
            return new String(Files.readAllBytes(Paths.get(new CheatClassLoaderDummyClass().getClass().getClassLoader().getResource(resourceFIleName).toURI())));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
class CheatClassLoaderDummyClass{//cheat class loader - for sql file loading
}
Espresso
quelle
0

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

public class FileUtils {

    public static String getResource(String classpathLocation) {
        try {
            String message = IOUtils.toString(FileUtils.class.getResourceAsStream(classpathLocation),
                    Charset.defaultCharset());
            return message;
        }
        catch (IOException e) {
            throw new RuntimeException("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

    @Test
    public void shouldDoSomething () {
        String json = FileUtils.getResource("/json/input.json");

        // Use json as part of test ...
    }
Bobmarksie
quelle
-2
public static byte[] readResoureStream(String resourcePath) throws IOException {
    ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
    InputStream in = CreateBffFile.class.getResourceAsStream(resourcePath);

    //Create buffer
    byte[] buffer = new byte[4096];
    for (;;) {
        int nread = in.read(buffer);
        if (nread <= 0) {
            break;
        }
        byteArray.write(buffer, 0, nread);
    }
    return byteArray.toByteArray();
}

Charset charset = StandardCharsets.UTF_8;
String content = new   String(FileReader.readResoureStream("/resource/...*.txt"), charset);
String lines[] = content.split("\\n");
Khắc Nghĩa Từ
quelle
Bitte fügen Sie Ihrer Antwort eine kurze Erklärung hinzu.
Nikolay Mihaylov