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


Ich benutze das Idiom unten seit einiger Zeit. Und es scheint am weitesten verbreitet zu sein, zumindest auf den Seiten, die ich besucht habe.

Gibt es eine bessere / andere Möglichkeit, eine Datei 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();
    }
}

1210
2017-11-28 18:32


Ursprung


Antworten:


Lesen Sie den gesamten Text aus einer Datei

Hier ist ein kompaktes, robustes Idiom für Java 7, eingepackt in eine Hilfsmethode:

static String readFile(String path, Charset encoding) 
  throws IOException 
{
  byte[] encoded = Files.readAllBytes(Paths.get(path));
  return new String(encoded, encoding);
}

Lesen Sie Textzeilen aus einer Datei

Java 7 hinzugefügt a Bequemlichkeitsmethode, um eine Datei als Textzeilen zu lesen, dargestellt als a List<String>. Dieser Ansatz ist "verlustbehaftet", da die Zeilentrennzeichen am Ende jeder Zeile entfernt werden.

List<String> lines = Files.readAllLines(Paths.get(path), encoding);

In Java 8, BufferedReader eine neue Methode hinzugefügt, lines() produzieren a Stream<String>. Wenn ein IOException beim Lesen der Datei gefunden wird, ist es in ein eingehüllt UncheckedIOException, schon seit Stream akzeptiert keine Lambdas, die geprüfte Ausnahmen auslösen.

try (BufferedReader r = Files.newBufferedReader(path, encoding)) {
  r.lines().forEach(System.out::println);
}

Da ist auch ein Files.lines() Methode, die etwas sehr ähnliches macht, die Rückkehr der Stream<String> direkt. Aber ich mag es nicht. Das Stream braucht ein close() Anruf; Dies ist in der API schlecht dokumentiert, und ich vermute, dass viele Leute dies nicht einmal bemerken Stream hat ein close() Methode. Ihr Code würde also sehr ähnlich aussehen:

try (Stream<String> lines = Files.lines(path, encoding)) {
  lines.forEach(System.out::println);
}

Der Unterschied ist, dass Sie eine haben Stream Ich versuche dies zu vermeiden, so dass ich nicht versehentlich versuche, den Stream zweimal aufzurufen.

Speicherauslastung

Die erste Methode, die Zeilenumbrüche beibehält, kann temporär Speicher erfordern, der um ein Vielfaches größer ist als die Datei, da für kurze Zeit der Inhalt der raw-Datei (ein Byte-Array) und die decodierten Zeichen (auch wenn codiert) jeweils 16 Bit umfassen als 8 Bits in der Datei) befinden sich im Speicher auf einmal. Es ist am sichersten auf Dateien anzuwenden, von denen Sie wissen, dass sie relativ zum verfügbaren Speicher klein sind.

Die zweite Methode, Zeilen lesen, ist in der Regel speichereffizienter, weil der Eingangsbyte-Puffer für die Decodierung nicht die gesamte Datei enthalten muss. Es ist jedoch immer noch nicht für Dateien geeignet, die relativ zum verfügbaren Speicher sehr groß sind.

Zum Lesen großer Dateien benötigen Sie ein anderes Design für Ihr Programm, das einen Textabschnitt aus einem Stream liest, verarbeitet und dann zum nächsten weiterleitet, wobei derselbe Speicherblock mit fester Größe wiederverwendet wird. Hier hängt "groß" von den Computerspezifikationen ab. Heutzutage kann dieser Schwellenwert viele Gigabyte RAM betragen. Die dritte Methode, die a Stream<String> ist eine Möglichkeit, dies zu tun, wenn Ihre Eingabe "Datensätze" zufällig einzelne Zeilen sind. (Verwendung der readLine() Methode von BufferedReader ist das Verfahrensäquivalent zu diesem Ansatz.)

Zeichenkodierung

Eine Sache, die in dem Beispiel in dem ursprünglichen Post fehlt, ist die Zeichencodierung. Es gibt einige spezielle Fälle, in denen die Plattform standardmäßig ist, was Sie wollen, aber sie sind selten, und Sie sollten in der Lage sein, Ihre Wahl zu begründen.

Das StandardCharsets Klasse definieren Sie einige Konstanten für die Kodierungen, die für alle Java-Laufzeiten benötigt werden:

String content = readFile("test.txt", StandardCharsets.UTF_8);

Der Plattformstandard ist verfügbar von das CharsetKlasse selbst:

String content = readFile("test.txt", Charset.defaultCharset());

Hinweis: Diese Antwort ersetzt weitgehend meine Java 6-Version. Das Dienstprogramm von Java 7 vereinfacht den Code sicher, und die alte Antwort, die einen zugeordneten Byte-Puffer verwendete, verhinderte, dass die Datei, die gelesen wurde, gelöscht wurde, bis der gemappte Puffer Speicherbereiniger war. Sie können die alte Version über den Link "editiert" in dieser Antwort anzeigen.


1251
2017-11-28 18:56



Gemeingüter FileUtils.readFileToString:

public static String readFileToString(File file)
                       throws IOException

Liest den Inhalt einer Datei mit der Standardcodierung in einen String   für die VM. Die Datei ist immer geschlossen.

Parameter:

  • file - Die zu lesende Datei darf nicht null sein

Kehrt zurück:   der Dateiinhalt, niemals null

Wirft:    - IOException - Im Falle eines E / A-Fehlers

Schon seit:   Commons IO 1.3.1

Der (indirekt) von dieser Klasse verwendete Code ist:

IOUtils.java unter Apache-Lizenz 2.0.

public static long copyLarge(InputStream input, OutputStream output)
       throws IOException {
   byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
   long count = 0;
   int n = 0;
   while (-1 != (n = input.read(buffer))) {
       output.write(buffer, 0, n);
       count += n;
   }
   return count;
}

Es ist dem von Ritche_W sehr ähnlich.


296
2017-11-28 18:44



Von diese Seite eine sehr schlanke Lösung:

Scanner scanner = new Scanner( new File("poem.txt") );
String text = scanner.useDelimiter("\\A").next();
scanner.close(); // Put this call in a finally block

oder

Scanner scanner = new Scanner( new File("poem.txt"), "UTF-8" );
String text = scanner.useDelimiter("\\A").next();
scanner.close(); // Put this call in a finally block

Wenn Sie den Zeichensatz festlegen möchten


159
2017-09-16 20:02



Wenn Sie nach einer Alternative suchen, bei der keine Bibliothek von Drittanbietern (z. Commons I / O), du kannst den ... benutzen Scanner Klasse:

private String readFile(String pathname) throws IOException {

    File file = new File(pathname);
    StringBuilder fileContents = new StringBuilder((int)file.length());
    Scanner scanner = new Scanner(file);
    String lineSeparator = System.getProperty("line.separator");

    try {
        while(scanner.hasNextLine()) {
            fileContents.append(scanner.nextLine() + lineSeparator);
        }
        return fileContents.toString();
    } finally {
        scanner.close();
    }
}

68
2017-11-28 19:00



Guave hat eine Methode ähnlich der von Commons IOUtils, die Willi aus Rohr erwähnte:

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

// ...

String text = Files.toString(new File(path), Charsets.UTF_8);

Bearbeiten von Oscar Reyes

Dies ist der (vereinfachte) zugrunde liegende Code der zitierten Bibliothek:

InputStream in = new FileInputStream(file);
byte[] b  = new byte[file.length()];
int len = b.length;
int total = 0;

while (total < len) {
  int result = in.read(b, total, len - total);
  if (result == -1) {
    break;
  }
  total += result;
}

return new String( b , Charsets.UTF_8 );

Bearbeiten (von Jonik): Das obige stimmt nicht mit dem Quellcode der letzten Guava-Versionen überein. Informationen zur aktuellen Quelle finden Sie in den Klassen Dateien, CharStreams, ByteSource und CharSource im com.google.common.io Paket.


63
2018-04-16 14:33



import java.nio.file.Files;

.......

 String readFile(String filename) {
            File f = new File(filename);
            try {
                byte[] bytes = Files.readAllBytes(f.toPath());
                return new String(bytes,"UTF-8");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return "";
    }

50
2017-10-29 08:51



Wenn Sie eine String-Verarbeitung (Parallelverarbeitung) benötigen, verfügt Java 8 über die großartige Stream-API.

String result = Files.lines(Paths.get("file.txt"))
                    .parallel() // for parallel processing 
                    .map(String::trim) // to change line   
                    .filter(line -> line.length() > 2) // to filter some lines by a predicate                        
                    .collect(Collectors.joining()); // to join lines

Weitere Beispiele finden Sie in JDK-Beispielen sample/lambda/BulkDataOperations das kann von heruntergeladen werden Oracle Java SE 8 Download-Seite 

Ein weiteres Beispiel für einen Liner

String out = String.join("\n", Files.readAllLines(Paths.get("file.txt")));

44
2017-11-28 19:56



Dieser Code wird Zeilenumbrüche normalisieren, die möglicherweise nicht das sind, was Sie wirklich tun möchten.

Hier ist eine Alternative, die das nicht tut, und die (IMO) einfacher zu verstehen ist als der NIO-Code (obwohl es immer noch verwendet wird) java.nio.charset.Charset):

public static String readFile(String file, String csName)
            throws IOException {
    Charset cs = Charset.forName(csName);
    return readFile(file, cs);
}

public static String readFile(String file, Charset cs)
            throws IOException {
    // No real need to close the BufferedReader/InputStreamReader
    // as they're only wrapping the stream
    FileInputStream stream = new FileInputStream(file);
    try {
        Reader reader = new BufferedReader(new InputStreamReader(stream, cs));
        StringBuilder builder = new StringBuilder();
        char[] buffer = new char[8192];
        int read;
        while ((read = reader.read(buffer, 0, buffer.length)) > 0) {
            builder.append(buffer, 0, read);
        }
        return builder.toString();
    } finally {
        // Potential issue here: if this throws an IOException,
        // it will mask any others. Normally I'd use a utility
        // method which would log exceptions and swallow them
        stream.close();
    }        
}

44
2017-10-28 07:04



String content = new String(Files.readAllBytes(Paths.get("readMe.txt")), "UTF-8");

Seit Java 7 können Sie es auf diese Weise tun.


40
2017-10-17 15:34