Java : Letzte n Zeilen einer RIESIGEN Datei lesen

Lesezeit: 8 Minuten

Java Letzte n Zeilen einer RIESIGEN Datei lesen
Gaurav Verma

Ich möchte die letzten n Zeilen einer sehr großen Datei lesen, ohne die gesamte Datei mit Java in einen Puffer-/Speicherbereich zu lesen.

Ich habe mich in den JDK-APIs und Apache Commons I/O umgesehen und kann keine für diesen Zweck geeignete finden.

Ich dachte an die Art und Weise, wie Tail oder weniger es unter UNIX macht. Ich glaube nicht, dass sie die gesamte Datei laden und dann die letzten paar Zeilen der Datei anzeigen. Es sollte eine ähnliche Möglichkeit geben, dasselbe auch in Java zu tun.

  • Siehe auch: Java: Die letzte Zeile einer Textdatei schnell lesen?

    – Hippietrail

    5. November ’12 um 18:22

Java Letzte n Zeilen einer RIESIGEN Datei lesen
akki_java

Ich fand es am einfachsten mit ReversedLinesFileReader von Apache Commons-io api. Diese Methode gibt Ihnen die Zeile von unten nach oben in einer Datei und Sie können angeben n_lines Wert, um die Zeilenanzahl anzugeben.

import org.apache.commons.io.input.ReversedLinesFileReader;


File file = new File("D:\file_name.xml");
int n_lines = 10;
int counter = 0; 
ReversedLinesFileReader object = new ReversedLinesFileReader(file);
while(counter < n_lines) {
    System.out.println(object.readLine());
    counter++;
}

  • Achtung: Bei jedem Anruf readLine(), der Cursor rückt vor. Dieser Code würde also eigentlich jede zweite Zeile verpassen, weil die Ausgabe von readLine() in dem while Aussage wird nicht erfasst.

    – aapierce

    23. Dezember ’15 um 22:42


  • Dieser Code ist etwas fehlerhaft, da readLine() zweimal aufgerufen wird. wie von aapierce erwähnt. Aber volle Punktzahl für ReversedLinesFileReader

    – vinksharma

    23. Mai ’17 um 21:11


  • @aapierce Die Kommentare von dir und vinksharma sind veraltet, oder? Die Bearbeitung von Mise hat das Problem wohl gelöst.. Es ist ein bisschen verwirrend, wenn die Kommentare nicht der aktuellen Version des Beitrags selbst entsprechen.

    – Daniel Eisenreich

    6. Nov. 18 um 8:36 Uhr

  • @DanielEisenreich Ja, es sieht so aus, als ob die Antwort bearbeitet wurde, seit ich meinen Kommentar vor 3 Jahren hinzugefügt habe. Es ist mir nicht klar, wie ich meinen Kommentar jetzt bearbeiten soll. Verzeihung!

    – aapierce

    6. November ’18 um 15:20

1641920234 656 Java Letzte n Zeilen einer RIESIGEN Datei lesen
paxdiablo

Wenn Sie a . verwenden RandomAccessFile, kannst du verwenden length und seek um zu einem bestimmten Punkt am Ende der Datei zu gelangen und dann von dort aus weiterzulesen.

Wenn Sie feststellen, dass nicht genügend Zeilen vorhanden sind, gehen Sie von diesem Punkt aus zurück und versuchen Sie es erneut. Sobald Sie herausgefunden haben, wo die Nte letzte Zeile beginnt, kann man dort suchen und einfach auslesen und ausdrucken.

Basierend auf Ihren Dateneigenschaften kann eine erste bestmögliche Annahme getroffen werden. Wenn es sich beispielsweise um eine Textdatei handelt, ist es möglich, dass die Zeilenlänge einen Durchschnitt von 132 nicht überschreitet. Um die letzten fünf Zeilen zu erhalten, beginnen Sie also 660 Zeichen vor dem Ende. Wenn Sie sich dann geirrt haben, versuchen Sie es erneut bei 1320 (Sie können sogar das, was Sie aus den letzten 660 Zeichen gelernt haben, anpassen, um das anzupassen – Beispiel: Wenn diese 660 Zeichen nur drei Zeilen wären, könnte der nächste Versuch 660 / 3 * 5 sein, plus vielleicht ein bisschen mehr für alle Fälle).

1641920234 777 Java Letzte n Zeilen einer RIESIGEN Datei lesen
Stephen C

RandomAccessFile ist ein guter Ausgangspunkt, wie in den anderen Antworten beschrieben. Es gibt eine wichtiger Vorbehalt obwohl.

Wenn Ihre Datei nicht mit einer Codierung von 1 Byte pro Zeichen codiert ist, wird die readLine() Methode wird bei Ihnen nicht funktionieren. Und readUTF() wird unter keinen Umständen funktionieren. (Es liest eine Zeichenfolge, der eine Zeichenanzahl vorangestellt ist …)

Stattdessen müssen Sie sicherstellen, dass Sie nach Zeilenendemarkierungen so suchen, dass die Zeichengrenzen der Codierung berücksichtigt werden. Für Kodierungen mit fester Länge (zB Varianten von UTF-16 oder UTF-32) müssen Sie Zeichen beginnend mit Bytepositionen extrahieren, die durch die Zeichengröße in Bytes teilbar sind. Bei Codierungen mit variabler Länge (zB UTF-8) müssen Sie nach einem Byte suchen, das muss das erste Byte eines Zeichens sein.

Bei UTF-8 ist das erste Byte eines Zeichens 0xxxxxxx oder 110xxxxx oder 1110xxxx oder 11110xxx. Alles andere ist entweder ein zweites / drittes Byte oder eine illegale UTF-8-Sequenz. Sehen Der Unicode-Standard, Version 5.2, Kapitel 3.9, Tabelle 3-7. Dies bedeutet, wie in der Kommentardiskussion hervorgehoben wird, dass alle 0x0A- und 0x0D-Bytes in einem ordnungsgemäß codierten UTF-8-Stream ein LF- oder CR-Zeichen darstellen. Daher ist das einfache Zählen der 0x0A- und 0x0D-Bytes eine gültige Implementierungsstrategie (für UTF-8), wenn wir davon ausgehen können, dass die anderen Arten von Unicode-Zeilentrennzeichen (0x2028, 0x2029 und 0x0085) nicht verwendet werden. Davon kann man nicht ausgehen, dann wäre der Code komplizierter.

Nachdem Sie eine richtige Zeichengrenze identifiziert haben, können Sie einfach anrufen new String(...) Übergeben von Byte-Array, Offset, Anzahl und Codierung und dann wiederholt Aufruf String.lastIndexOf(...) Zeilenende zu zählen.

  • +1 für die Erwähnung des Vorbehalts. Ich denke, für UTF-8 kann das Problem einfacher gemacht werden, indem nach ‘n’ gesucht wird … Zumindest scheint das Jon Skeet in seiner Antwort auf eine verwandte Frage zu implizieren … Scheint, dass ‘n’ nur vorkommen kann als gültiges Zeichen in UTF-8 und niemals in den ‘zusätzlichen Bytes’…

    – Stijn de Witt

    7. August ’14 um 21:53

  • Ja, für UTF-8 ist es einfach. UTF-8 codiert Zeichen entweder als einzelnes Byte (alle ASCII-Zeichen) oder als mehrere Bytes (alle anderen Unicode-Zeichen). Zum Glück für uns ist Newline ein ASCII-Zeichen und in UTF-8 enthält kein Multibyte-Zeichen Bytes, die auch gültige ASCII-Zeichen sind. Das heißt, wenn Sie ein Array von Bytes nach ASCII-Neuzeilen durchsuchen und es finden, werden Sie wissen es ist ein Zeilenumbruch und kein Teil eines anderen Multi-Byte-Zeichens. ich schrieb a Blogeintrag Das hat eine schöne Tabelle, die dies veranschaulicht.

    – Stijn de Witt

    10. August ’14 um 12:29

  • Das Problem sind 1) Zeichenkodierungen, bei denen das Byte 0x0a kein Zeilenumbruch ist (zB UTF-16), und 2) die Tatsache, dass es andere Unicode-Zeilentrennzeichen-Codepunkte gibt; z.B 0x2028, 0x2029 und 0x0085

    – Stephen C

    10. August ’14 um 12:46

  • Ja, das einfache Szenario gilt nur für UTF-8 und wenn Zeilenumbrüche entweder als CRLF oder nur als LF kodiert sind … Ich denke jedoch, dass dies in der Praxis die meisten realen Szenarien abdeckt. UTF-16 ist ziemlich selten, wenn es um die Kodierung von Textdateien geht (es wird oft im Speicher verwendet, aber nicht sehr oft in Dateien) und ich kenne nicht viele Editoren, die diese anderen Unicode-Zeilentrennzeichen einfügen …

    – Stijn de Witt

    10. August ’14 um 14:11

1641920234 340 Java Letzte n Zeilen einer RIESIGEN Datei lesen
Torsten Simon

Der ReversedLinesFileReader finden Sie im Apache Commons IO Java-Bibliothek.

    int n_lines = 1000;
    ReversedLinesFileReader object = new ReversedLinesFileReader(new File(path));
    String result="";
    for(int i=0;i<n_lines;i++){
        String line=object.readLine();
        if(line==null)
            break;
        result+=line;
    }
    return result;

ich fand RandomAccessFile und andere Buffer Reader-Klassen zu langsam für mich. Nichts kann schneller sein als ein tail -<#lines>. Also das war für mich die beste Lösung.

public String getLastNLogLines(File file, int nLines) {
    StringBuilder s = new StringBuilder();
    try {
        Process p = Runtime.getRuntime().exec("tail -"+nLines+" "+file);
        java.io.BufferedReader input = new java.io.BufferedReader(new java.io.InputStreamReader(p.getInputStream()));
        String line = null;
    //Here we first read the next line into the variable
    //line and then check for the EOF condition, which
    //is the return value of null
    while((line = input.readLine()) != null){
            s.append(line+'n');
        }
    } catch (java.io.IOException e) {
        e.printStackTrace();
    }
    return s.toString();
}

  • Hinausgehen zu tail kann eine sehr kostspielige Angelegenheit sein, je nachdem, wie viel Speicher Sie haben. Und es ist auch Unix-spezifisch.

    – Grau

    4. November ’13 um 20:12

  • Keine generische Lösung. Ähnlich wie bei tail können mehrere Dienstprogramme verwendet werden. Dies ist nicht das, was in Frage gestellt wurde.

    – shaILU

    15. September ’20 um 19:10 Uhr

1641920234 241 Java Letzte n Zeilen einer RIESIGEN Datei lesen
Gemeinschaft

RundschreibenFifoPuffer von Apache Commons. Antwort aus einer ähnlichen Frage unter So lesen Sie die letzten 5 Zeilen einer .txt-Datei in Java ein

Beachten Sie, dass diese Klasse in Apache Commons Collections 4 anscheinend umbenannt wurde in RundschreibenFifoQueue

  • Hinausgehen zu tail kann eine sehr kostspielige Angelegenheit sein, je nachdem, wie viel Speicher Sie haben. Und es ist auch Unix-spezifisch.

    – Grau

    4. November ’13 um 20:12

  • Keine generische Lösung. Ähnlich wie bei tail können mehrere Dienstprogramme verwendet werden. Dies ist nicht das, was in Frage gestellt wurde.

    – shaILU

    15. September ’20 um 19:10 Uhr

Java Letzte n Zeilen einer RIESIGEN Datei lesen
Uday Kumar

package com.uday;

import java.io.File;
import java.io.RandomAccessFile;

public class TailN {
    public static void main(String[] args) throws Exception {
        long startTime = System.currentTimeMillis();

        TailN tailN = new TailN();
        File file = new File("/Users/udakkuma/Documents/workspace/uday_cancel_feature/TestOOPS/src/file.txt");
        tailN.readFromLast(file);

        System.out.println("Execution Time : " + (System.currentTimeMillis() - startTime));

    }

    public void readFromLast(File file) throws Exception {
        int lines = 3;
        int readLines = 0;
        StringBuilder builder = new StringBuilder();
        try (RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r")) {
            long fileLength = file.length() - 1;
            // Set the pointer at the last of the file
            randomAccessFile.seek(fileLength);

            for (long pointer = fileLength; pointer >= 0; pointer--) {
                randomAccessFile.seek(pointer);
                char c;
                // read from the last, one char at the time
                c = (char) randomAccessFile.read();
                // break when end of the line
                if (c == 'n') {
                    readLines++;
                    if (readLines == lines)
                        break;
                }
                builder.append(c);
                fileLength = fileLength - pointer;
            }
            // Since line is read from the last so it is in reverse order. Use reverse
            // method to make it correct order
            builder.reverse();
            System.out.println(builder.toString());
        }

    }
}

.

373090cookie-checkJava : Letzte n Zeilen einer RIESIGEN Datei lesen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy