1789 Stimmen

Wie erstelle ich eine Java-Zeichenfolge aus dem Inhalt einer Datei?

Ich verwende das untenstehende Idiom schon seit einiger Zeit. Und es scheint das weit verbreitetste zu sein, zumindest auf den Seiten, die ich besucht habe.

Gibt es einen besseren/anderen Weg, um eine Datei in einen String in Java zu lesen?

private String readFile(String file) throws IOException {
    BufferedReader reader = new BufferedReader(new FileReader (file));
    String line = null;
    StringBuilder stringBuilder = new StringBuilder();
    String ls = System.getProperty("line.separator");

    try {
        while((line = reader.readLine()) != null) {
            stringBuilder.append(line);
            stringBuilder.append(ls);
        }

        return stringBuilder.toString();
    } finally {
        reader.close();
    }
}

8 Stimmen

Kann mir jemand auf eine sehr einfache Weise erklären, was es mit dem NIO auf sich hat? Jedes Mal, wenn ich darüber lese, verliere ich mich in der x-ten Erwähnung eines Kanals :(

8 Stimmen

Bitte beachten Sie, dass nicht garantiert ist, dass der Zeilentrenner in der Datei derselbe ist wie der Zeilentrenner des Systems.

7 Stimmen

Der obige Code hat einen Fehler, bei dem ein zusätzliches Zeilenumbruchzeichen in der letzten Zeile hinzugefügt wird. Es sollte etwas Ähnliches wie folgt sein: if ( (line = reader.readLine()) != null) { stringBuilder.append( line ); } while ( (line = reader.readLine()) != null) { stringBuilder.append( ls ); stringBuilder.append( line ); }

1861voto

erickson Punkte 256579

Alle Texte aus einer Datei lesen

In Java 11 wurde die readString()-Methode hinzugefügt, um kleine Dateien als String zu lesen und Zeilenenden beizubehalten:

String inhalt = Files.readString(pfad, codierung);

Für Versionen zwischen Java 7 und 11 bietet sich hier ein kompakter, robuster Idiom, eingebettet in einer Hilfsmethode:

static String dateiLesen(String pfad, Charset codierung)
  throws IOException
{
  byte[] codiert = Files.readAllBytes(Paths.get(pfad));
  return new String(codiert, codierung);
}

Linien mit Text aus einer Datei lesen

In Java 7 wurde eine Bequemlichkeitsmethode hinzugefügt, um eine Datei als Textzeilen zu lesen, dargestellt als eine List. Dieser Ansatz ist "verlustbehaftet", da die Zeilenumbrüche am Ende jeder Zeile entfernt werden.

List zeilen = Files.readAllLines(Paths.get(pfad), codierung);

In Java 8 wurde die Files.lines()-Methode hinzugefügt, um einen Stream zu erzeugen. Auch diese Methode entfernt Zeilenumbrüche. Wenn während des Dateilesevorgangs ein IOException auftritt, wird es in eine UncheckedIOException eingepackt, da Stream keine Lambdas akzeptiert, die überprüfbare Ausnahmen werfen.

try (Stream zeilen = Files.lines(pfad, codierung)) {
  zeilen.forEach(System.out::println);
}

Dieser Stream benötigt einen close()-Aufruf; dies ist in der API schlecht dokumentiert, und ich vermute, dass viele Leute nicht einmal bemerken, dass Stream eine close()-Methode hat. Stellen Sie sicher, dass Sie einen ARM-Block wie gezeigt verwenden.

Wenn Sie mit einer Quelle arbeiten, die nicht eine Datei ist, können Sie die lines()-Methode in BufferedReader verwenden.

Speicherauslastung

Wenn Ihre Datei im Vergleich zu Ihrem verfügbaren Speicher klein genug ist, könnte das Lesen der gesamten Datei auf einmal gut funktionieren. Ist Ihre Datei jedoch zu groß, könnte es besser sein, eine Zeile nach der anderen zu lesen, zu verarbeiten und dann zu verwerfen, bevor Sie zur nächsten übergehen. Das Stream-Verarbeiten auf diese Weise kann die Gesamtgröße der Datei als Faktor für Ihren Speicherbedarf beseitigen.

Zeichenkodierung

Etwas, das im Beispiel im Originalbeitrag fehlt, ist die Zeichenkodierung. Diese Kodierung kann im Allgemeinen nicht aus der Datei selbst bestimmt werden und erfordert Metadaten wie einen HTTP-Header, um diese wichtige Information zu übermitteln.

Die Klasse StandardCharsets definiert einige Konstanten für die Kodierungen, die von allen Java-Laufzeiten benötigt werden:

String inhalt = dateiLesen("test.txt", StandardCharsets.UTF_8);

Das plattformspezifische Standardenkodierung ist über die Klasse Charset selbst verfügbar:

String inhalt = dateiLesen("test.txt", Charset.defaultCharset());

Es gibt einige spezielle Fälle, in denen das plattformspezifische Standardverhalten angemessen ist, aber sie sind selten. Sie sollten Ihre Wahl begründen können, da das plattformspezifische Standardverhalten nicht portabel ist. Ein Beispiel, wo es richtig sein könnte, ist beim Lesen von Standardinput oder Schreiben von Standardausgabe.


Hinweis: Diese Antwort ersetzt größtenteils meine Java 6-Version. Die Nützlichkeit von Java 7 vereinfacht den Code sicher, und die alte Antwort, die einen zugeordneten Byte-Buffer verwendete, verhinderte, dass die gelesene Datei gelöscht wurde, bis der zugeordnete Buffer vom Garbage-Collector gesammelt wurde. Sie können die alte Version über den "bearbeitet" Link in dieser Antwort anzeigen.

36 Stimmen

Hinweis: Nachdem ich diesen Code ein wenig getestet habe, habe ich herausgefunden, dass Sie die Datei nicht zuverlässig direkt nach dem Lesen mit dieser Methode löschen können, was in einigen Fällen kein Problem sein könnte, aber nicht in meinem. Könnte es mit diesem Problem zusammenhängen: bugs.sun.com/bugdatabase/view_bug.do?bug_id=4715154 ? Letztendlich entschied ich mich für den Vorschlag von Jon Skeet, der nicht unter diesem Bug leidet. Wie auch immer, ich wollte nur die Information für andere Personen bereitstellen, falls...

2 Stimmen

OK, ich habe meinen Kommentar gelöscht, da er nicht mehr zutrifft.

1 Stimmen

Die Speicherauslastung hängt vom Anwendungsfall ab. Wenn Sie eine Datei zeilenweise verarbeiten können, ohne die verarbeiteten Zeilen speichern zu müssen, erfordert das Streamen über die Zeilen am wenigsten Speicher. Wenn Sie jedoch alle Zeilen im Speicher benötigen, ist eine Liste von String-Objekten, eine für jede Zeile, alles andere als preiswert. Der Overhead könnte sogar größer sein als bei einem Byte-Array und einem (einzigen) String im Speicher. Wenn bestimmte Voraussetzungen erfüllt sind, ist die erste Lösung, Files.readString(…), die einzige, die ohne zusätzlichen Speicherbedarf funktionieren kann.

405voto

DaWilli Punkte 4738

Wenn Sie bereit sind, eine externe Bibliothek zu verwenden, schauen Sie sich Apache Commons IO (200KB JAR) an. Es enthält eine org.apache.commons.io.FileUtils.readFileToString() Methode, die es Ihnen ermöglicht, eine gesamte Datei mit einer Codezeile in einen String zu lesen.

Beispiel:

import java.io.*;
import java.nio.charset.*;
import org.apache.commons.io.*;

public String readFile() throws IOException {
    File file = new File("data.txt");
    return FileUtils.readFileToString(file, StandardCharsets.UTF_8);
}

190voto

Pablo Grisafi Punkte 5003

Eine sehr schlankere Lösung basierend auf Scanner:

Scanner scanner = new Scanner( new File("poem.txt") );
String text = scanner.useDelimiter("\\A").next();
scanner.close(); // Setzen Sie diesen Aufruf in einen finally-Block

Oder, wenn Sie den Zeichensatz festlegen möchten:

Scanner scanner = new Scanner( new File("poem.txt"), "UTF-8" );
String text = scanner.useDelimiter("\\A").next();
scanner.close(); // Setzen Sie diesen Aufruf in einen finally-Block

Oder mit einem try-with-resources-Block, der scanner.close() für Sie aufrufen wird:

try (Scanner scanner = new Scanner( new File("poem.txt"), "UTF-8" )) {
    String text = scanner.useDelimiter("\\A").next();
}

Vergessen Sie nicht, dass der Scanner-Konstruktor eine IOException auslösen kann. Und vergessen Sie nicht, java.io und java.util zu importieren.

Quelle: Pat Niemeyers Blog

4 Stimmen

\\A funktioniert, weil es kein "anderer Anfang der Datei" gibt, also liest du tatsächlich das letzte Token...das auch das erste ist. Habe nie mit \\Z probiert. Beachte auch, dass du alles lesen kannst, was lesbar ist, wie Dateien, InputStreams, Kanäle...Manchmal verwende ich diesen Code, um aus dem Anzeigefenster von Eclipse zu lesen, wenn ich mir nicht sicher bin, ob ich eine Datei oder eine andere lese...ja, der Klassenpfad verwirrt mich.

21 Stimmen

Scanner implementiert Closeable (es ruft close auf der Quelle auf) - daher sollte es zwar elegant sein, aber nicht wirklich ein Einzeiler sein. Die Standardgröße des Puffers beträgt 1024, aber Scanner wird die Größe nach Bedarf erhöhen (siehe Scanner#makeSpace())

168voto

Jobin Punkte 5104
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;

Java 7

String content = new String(Files.readAllBytes(Paths.get("readMe.txt")), StandardCharsets.UTF_8);

Java 11

String content = Files.readString(Paths.get("readMe.txt"));

81voto

Dónal Punkte 180956

Wenn Sie nach einer Alternative suchen, die keine Verwendung einer Third-Party-Bibliothek (z.B. Commons I/O) beinhaltet, können Sie die Scanner-Klasse verwenden:

private String readFile(String pathname) throws IOException {

    File file = new File(pathname);
    StringBuilder fileContents = new StringBuilder((int)file.length());        

    try (Scanner scanner = new Scanner(file)) {
        while(scanner.hasNextLine()) {
            fileContents.append(scanner.nextLine() + System.lineSeparator());
        }
        return fileContents.toString();
    }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X