überschreiben - java textdatei erstellen und speichern




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

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();
    }
}

Lesen Sie den gesamten Text aus einer Datei

Hier ist ein kompaktes, robustes Idiom für Java 7, verpackt in einer 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 hat eine bequeme Methode hinzugefügt , um eine Datei als Textzeilen zu lesen, dargestellt als eine 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 hat BufferedReader eine neue Methode, lines() hinzugefügt, um einen Stream<String> zu erzeugen. Wenn beim Lesen der Datei eine IOException , wird sie in eine UncheckedIOException , da Stream keine Lambdas akzeptiert, die geprüfte Ausnahmen IOException .

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

Es gibt auch eine Files.lines() -Methode, die etwas sehr ähnliches tut und den Stream<String> direkt Files.lines() . Aber ich mag es nicht. Der Stream benötigt einen close() -Aufruf; Das ist in der API schlecht dokumentiert, und ich vermute, dass viele Leute nicht einmal bemerken, dass Stream eine close() -Methode hat. 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 einer Variable einen Stream zugewiesen haben, und ich versuche das 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 einen Stream<String> ist eine Möglichkeit, dies zu tun, wenn Ihre Eingabe "Datensätze" zufällig einzelne Zeilen sind. (Die 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.

Die StandardCharsets Klasse definiert einige Konstanten für die Kodierungen, die für alle Java-Laufzeiten erforderlich sind:

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

Der Plattformstandard ist von der Charset Klasse selbst verfügbar:

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.


Basierend auf @ Ericksons Antwort können Sie Folgendes verwenden:

public void readAll(String fileName) throws IOException {
    List<String> lines = Files.readAllLines(new File(fileName).toPath());
    return String.join("\n", lines.toArray(new String[lines.size()]));
}

Benutze Code:

File file = new File("input.txt");
BufferedInputStream bin = new BufferedInputStream(new FileInputStream(
                file));
byte[] buffer = new byte[(int) file.length()];
bin.read(buffer);
String fileStr = new String(buffer);

fileStr enthält die Ausgabe in String.


Commons FileUtils.readFileToString :

public static String readFileToString(File file)
                       throws IOException

Liest den Inhalt einer Datei in eine Zeichenfolge unter Verwendung der Standardcodierung für die VM. Die Datei ist immer geschlossen.

Parameter:

  • file - Die zu lesende Datei darf nicht null sein

Rückgabe: Der Dateiinhalt, niemals null

Auslöser: - IOException - bei einem E / A-Fehler

Seit: Commons IO 1.3.1

Der (indirekt) von dieser Klasse verwendete Code ist:

IOUtils.java unter Apache License 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.


Dieser verwendet die Methode RandomAccessFile.readFully , scheint aus JDK 1.0 verfügbar zu sein!

public static String readFileContent(String filename, Charset charset) throws IOException {
    RandomAccessFile raf = null;
    try {
        raf = new RandomAccessFile(filename, "r");
        byte[] buffer = new byte[(int)raf.length()];
        raf.readFully(buffer);
        return new String(buffer, charset);
    } finally {
        closeStream(raf);
    }
} 


private static void closeStream(Closeable c) {
    if (c != null) {
        try {
            c.close();
        } catch (IOException ex) {
            // do nothing
        }
    }
}

Eine Datei als Binärdatei lesen und am Ende konvertieren

public static String readFileAsString(String filePath) throws IOException {
    DataInputStream dis = new DataInputStream(new FileInputStream(filePath));
    try {
        long len = new File(filePath).length();
        if (len > Integer.MAX_VALUE) throw new IOException("File "+filePath+" too large, was "+len+" bytes.");
        byte[] bytes = new byte[(int) len];
        dis.readFully(bytes);
        return new String(bytes, "UTF-8");
    } finally {
        dis.close();
    }
}

Es gibt eine Variante desselben Themas, die anstelle einer while-Schleife eine for-Schleife verwendet, um den Geltungsbereich der Zeilenvariablen zu begrenzen. Ob es "besser" ist, ist eine Frage des persönlichen Geschmacks.

for(String line = reader.readLine(); line != null; line = reader.readLine()) {
    stringBuilder.append(line);
    stringBuilder.append(ls);
}

Ich kann noch keine anderen Einträge kommentieren, also werde ich es hier lassen.

Eine der besten Antworten hier ( https://.com/a/326448/1521167 ):

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();
}
}

hat immer noch einen Fehler. Es fügt immer ein neues Zeilenkürzel am Ende von string ein, was einige seltsame Fehler verursachen kann. Mein Vorschlag ist es zu ändern:

    private String readFile(String pathname) throws IOException {
    File file = new File(pathname);
    StringBuilder fileContents = new StringBuilder((int) file.length());
    Scanner scanner = new Scanner(new BufferedReader(new FileReader(file)));
    String lineSeparator = System.getProperty("line.separator");

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

In einer Zeile (Java 8), vorausgesetzt, Sie haben einen Reader:

String sMessage = String.join("\n", reader.lines().collect(Collectors.toList()));

Java versucht extrem allgemein und flexibel zu sein. Als Ergebnis ist etwas, das in einer Skriptsprache relativ einfach ist (Ihr Code würde in Python durch " open(file).read() " ersetzt) ​​ist viel komplizierter. Es scheint keinen kürzeren Weg zu geben, außer mit einer externen Bibliothek (wie Willi aus Rohr erwähnt). Deine Optionen:

  • Verwenden Sie eine externe Bibliothek.
  • Kopieren Sie diesen Code in alle Ihre Projekte.
  • Erstellen Sie Ihre eigene Mini-Bibliothek, die häufig verwendete Funktionen enthält.

Ihre beste Wette ist wahrscheinlich die zweite, da sie die wenigsten Abhängigkeiten hat.


Nach Ctrl + F'ing nach dem Scanner denke ich, dass die Scannerlösung auch aufgelistet sein sollte. In der am einfachsten zu lesenden Mode geht es so:

public String fileToString(File file, Charset charset) {
  Scanner fileReader = new Scanner(file, charset);
  fileReader.useDelimiter("\\Z"); // \Z means EOF.
  String out = fileReader.next();
  fileReader.close();
  return out;
}

Wenn Sie Java 7 oder neuer verwenden (und Sie sollten es wirklich tun), sollten Sie Try-with-resources verwenden, um den Code leichter lesbar zu machen. Kein dot-close-Zeug mehr über alles. Aber das ist meistens eine stilistische Entscheidung.

Ich poste dies hauptsächlich für die Fertigstellung, da, wenn Sie dies viel tun müssen, sollten Dinge in java.nio.file.Files , die die Arbeit besser machen sollten.

Mein Vorschlag wäre, Files#readAllBytes(Path) zu verwenden, um alle Bytes zu Files#readAllBytes(Path) und sie an den neuen String (byte [] Charset) zu übergeben, um einen String daraus zu erhalten, dem Sie vertrauen können. Charsets werden zu deinen Lebzeiten gemein zu dir sein, also hüte dich jetzt vor diesem Zeug.

Andere haben Code und solche Sachen gegeben, und ich will ihren Ruhm nicht stehlen. ;)


Sie können versuchen, Scanner und File-Klasse, ein paar Zeilen Lösung

 try
{
  String content = new Scanner(new File("file.txt")).useDelimiter("\\Z").next();
  System.out.println(content);
}
catch(FileNotFoundException e)
{
  System.out.println("not found!");
}

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 , die von der Oracle Java SE 8-Download-Seite heruntergeladen werden können

Ein weiteres Beispiel für einen Liner

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

Wenn Sie keinen Zugriff auf Dateien haben, tun Sie Folgendes:

static String readFile(File file, String charset)
        throws IOException
{
    FileInputStream fileInputStream = new FileInputStream(file);
    byte[] buffer = new byte[fileInputStream.available()];
    int length = fileInputStream.read(buffer);
    fileInputStream.close();
    return new String(buffer, 0, length, charset);
}

Wenn es eine Textdatei ist, warum nicht Apache commons-io verwenden ?

Es hat die folgende Methode

public static String readFileToString(File file) throws IOException

Wenn Sie die Zeilen als Liste verwenden möchten

public static List<String> readLines(File file) throws IOException

Wenn sich Ihre Datei zufällig in einem Jar befindet, können Sie auch Folgendes verwenden:

public String fromFileInJar(String path) {
    try ( Scanner scanner 
            = new Scanner(getClass().getResourceAsStream(path))) {
        return scanner.useDelimiter("\\A").next();
    }
}

Der Pfad sollte zum Beispiel mit Ihrem Jar beginnen

my.jar/com/some/thing/a.txt

Dann möchtest du es so aufrufen:

String myTxt = fromFileInJar("/com/com/thing/a.txt");

fileInputStream.available() bei der Verwendung von fileInputStream.available() die zurückgegebene Ganzzahl nicht die tatsächliche Dateigröße darstellen muss, sondern die geschätzte Menge an Bytes, die das System aus dem Stream lesen kann, ohne IO zu blockieren. Ein sicherer und einfacher Weg könnte so aussehen

public String readStringFromInputStream(FileInputStream fileInputStream) {
    StringBuffer stringBuffer = new StringBuffer();
    try {
        byte[] buffer;
        while (fileInputStream.available() > 0) {
            buffer = new byte[fileInputStream.available()];
            fileInputStream.read(buffer);
            stringBuffer.append(new String(buffer, "ISO-8859-1"));
        }
    } catch (FileNotFoundException e) {
    } catch (IOException e) { }
    return stringBuffer.toString();
}

Es sollte berücksichtigt werden, dass dieser Ansatz nicht für Multi-Byte-Zeichenkodierungen wie UTF-8 geeignet ist.


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

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


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 "";
    }

public static String slurp (final File file)
throws IOException {
    StringBuilder result = new StringBuilder();

    try {
        BufferedReader reader = new BufferedReader(new FileReader(file));

        char[] buf = new char[1024];

        int r = 0;

        while ((r = reader.read(buf)) != -1) {
            result.append(buf, 0, r);
        }
    }
    finally {
        reader.close();
    }

    return result.toString();
}






io