Wie lese ich eine bestimmte Zeile mit der bestimmten Zeilennummer aus einer Datei in Java?

90

Gibt es in Java eine Methode zum Lesen einer bestimmten Zeile aus einer Datei? Lesen Sie beispielsweise Zeile 32 oder eine andere Zeilennummer.

Dreieinigkeit
quelle
5
Ich weiß, dass ich sehr spät dran bin, aber falls jemand diese Frage gefunden hat: Beachten Sie, dass eine Datei nur eine Folge von Bytes ist. Und eine neue Zeile ist nur ein Zeichen (zwei unter Windows), und ein Zeichen ist nur ein (oder mehr, abhängig von der Codierung) Byte. Und ohne einen Index der Positionen eines Bytes in einer Datei zu haben, besteht die einzige Möglichkeit zu wissen, wo sich diese Bytes befinden, darin, sie zu lesen und danach zu suchen. (Dies bedeutet jedoch nicht, dass Sie die gesamte Datei in den Speicher laden müssen).
Szgal

Antworten:

71

Wenn Sie keine Vorkenntnisse über die Zeilen in der Datei haben, können Sie nicht direkt auf die 32. Zeile zugreifen, ohne die 31 vorherigen Zeilen gelesen zu haben.

Das gilt für alle Sprachen und alle modernen Dateisysteme.

So effektiv lesen Sie einfach Zeilen, bis Sie die 32. gefunden haben.

Joachim Sauer
quelle
4
Das "Vorwissen" kann so einfach sein wie das genaue Liniengrößenmuster in der Datei, sodass Sie nach einer bestimmten Position suchen können.
Murali VP
2
@Murali: natürlich. Es kann sich auch um einen Index der Zeilennummer zum Byte-Offset oder eine beliebige Kombination davon handeln.
Joachim Sauer
101

Für kleine Dateien:

String line32 = Files.readAllLines(Paths.get("file.txt")).get(32)

Für große Dateien:

try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) {
    line32 = lines.skip(31).findFirst().get();
}
aioobe
quelle
Dies gibt java.nio.charset.MalformedInputException zurück: Eingabelänge = 1 bei Verwendung mit einem
kanadischer
Das ist kein Problem mit dem Code, den ich gepostet habe, sondern ein Problem mit der Codierung Ihrer Datei. Siehe diesen Beitrag .
Aioobe
3
"Beachten Sie, dass diese Methode für einfache Fälle gedacht ist, in denen es bequem ist, alle Zeilen in einem einzigen Vorgang zu lesen. Sie ist nicht zum Lesen großer Dateien gedacht." - Javadoc von Files.readAllLines ()
PragmaticProgrammer
Der folgende Code erfordert API Level 26 in Android. Wenn unsere min weniger als dieses Niveau ist, dann funktioniert es nicht
Ali Azaz Alam
38

Nicht das ich wüsste, aber was Sie tun könnten, ist die ersten 31 Zeilen zu durchlaufen und nichts mit der Funktion readline () von BufferedReader zu tun

FileInputStream fs= new FileInputStream("someFile.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(fs));
for(int i = 0; i < 31; ++i)
  br.readLine();
String lineIWant = br.readLine();
Chris Thompson
quelle
1
Bitte beachten Sie, dass Sie hier die Zeilennummer 30 lesen, die 31. Zeile, da wir die Zeilennummern mit 0 beginnen. Daher würde ich vorschlagen, sie so zu ändern, dass sie genau der Frage entspricht.
Kiedysktos
15

Joachim ist natürlich richtig, und eine alternative Implementierung zu Chris '(für kleine Dateien nur, weil die gesamte Datei geladen wird) könnte darin bestehen, commons-io von Apache zu verwenden (obwohl Sie möglicherweise keine neue Abhängigkeit nur für einführen möchten Dies, wenn Sie es aber auch für andere Dinge nützlich finden, könnte es sinnvoll sein.

Beispielsweise:

String line32 = (String) FileUtils.readLines(file).get(31);

http://commons.apache.org/io/api-release/org/apache/commons/io/FileUtils.html#readLines(java.io.File , java.lang.String)

Charlie Collins
quelle
2
Dies würde jedoch die gesamte Datei in den Speicher laden, bevor zur 32. Zeile übergegangen wird. Dies ist bei einer großen Datei möglicherweise nicht praktikabel und langsamer als das Lesen, wenn die 32. Zeile gefunden wird ...
beny23
Guter Punkt, ja. Ich habe das in Testfällen verwendet, in denen die Testdateien klein waren, obwohl große Dateien übereinstimmten, kein guter Ansatz.
Charlie Collins
Der Antwortbeitrag wurde aktualisiert, um zu berücksichtigen, dass FileUtils in diesem Anwendungsfall eine schlechte Idee ist, wenn Sie eine große Datei haben und nichts über Zeile X hinaus benötigen.
Charlie Collins
11

Sie können den Indexed-File-Reader (Apache License 2.0) ausprobieren . Die Klasse IndexedFileReader verfügt über eine Methode namens readLines (int from, int to), die eine SortedMap zurückgibt, deren Schlüssel die Zeilennummer und der Wert die gelesene Zeile ist.

Beispiel:

File file = new File("src/test/resources/file.txt");
reader = new IndexedFileReader(file);

lines = reader.readLines(6, 10);
assertNotNull("Null result.", lines);
assertEquals("Incorrect length.", 5, lines.size());
assertTrue("Incorrect value.", lines.get(6).startsWith("[6]"));
assertTrue("Incorrect value.", lines.get(7).startsWith("[7]"));
assertTrue("Incorrect value.", lines.get(8).startsWith("[8]"));
assertTrue("Incorrect value.", lines.get(9).startsWith("[9]"));
assertTrue("Incorrect value.", lines.get(10).startsWith("[10]"));      

Im obigen Beispiel wird eine Textdatei gelesen, die aus 50 Zeilen im folgenden Format besteht:

[1] The quick brown fox jumped over the lazy dog ODD
[2] The quick brown fox jumped over the lazy dog EVEN

Disclamer: Ich habe diese Bibliothek geschrieben

jramoyo
quelle
6

Obwohl, wie in anderen Antworten gesagt, es nicht möglich ist, zur genauen Linie zu gelangen, ohne vorher den Versatz (Zeiger) zu kennen. Ich habe dies erreicht, indem ich eine temporäre Indexdatei erstellt habe, in der die Versatzwerte jeder Zeile gespeichert werden. Wenn die Datei klein genug ist, können Sie die Indizes (Offset) einfach im Speicher speichern, ohne eine separate Datei dafür zu benötigen.

The offsets can be calculated by using the RandomAccessFile

    RandomAccessFile raf = new RandomAccessFile("myFile.txt","r"); 
    //above 'r' means open in read only mode
    ArrayList<Integer> arrayList = new ArrayList<Integer>();
    String cur_line = "";
    while((cur_line=raf.readLine())!=null)
    {
    arrayList.add(raf.getFilePointer());
    }
    //Print the 32 line
    //Seeks the file to the particular location from where our '32' line starts
    raf.seek(raf.seek(arrayList.get(31));
    System.out.println(raf.readLine());
    raf.close();

Weitere Informationen finden Sie auch in den Java-Dokumenten: https://docs.oracle.com/javase/8/docs/api/java/io/RandomAccessFile.html#mode

Komplexität : Dies ist O (n), da die gesamte Datei einmal gelesen wird. Bitte beachten Sie die Speicheranforderungen. Wenn es zu groß ist, um im Speicher zu sein, erstellen Sie eine temporäre Datei, in der die Offsets anstelle von ArrayList wie oben gezeigt gespeichert sind.

Hinweis : Wenn alles, was Sie wollen, in der Zeile '32' steht, müssen Sie nur die readLine () aufrufen, die auch über andere Klassen '32' verfügbar ist. Der obige Ansatz ist nützlich, wenn Sie eine bestimmte Zeile (natürlich basierend auf der Zeilennummer) mehrmals abrufen möchten.

Vielen Dank !

ShankarDaruga
quelle
Es muss etwas bearbeitet werden, damit der obige Code funktioniert. Und wenn jemand Zeichensatz benötigt, sollten Sie dies wirklich lesen: stackoverflow.com/a/37275357/3198960
rufushuang
5

Ein anderer Weg.

try (BufferedReader reader = Files.newBufferedReader(
        Paths.get("file.txt"), StandardCharsets.UTF_8)) {
    List<String> line = reader.lines()
                              .skip(31)
                              .limit(1)
                              .collect(Collectors.toList());

    line.stream().forEach(System.out::println);
}
rhel.user
quelle
1
Elegant, ich mag es.
Florescu Cătălin
4

Nein, es sei denn, in diesem Dateiformat sind die Zeilenlängen im Voraus festgelegt (z. B. alle Zeilen mit fester Länge), müssen Sie zeilenweise iterieren, um sie zu zählen.

Brühe
quelle
2

Wenn Sie über eine Textdatei sprechen, gibt es wirklich keine Möglichkeit, dies zu tun, ohne alle vorangegangenen Zeilen zu lesen. Schließlich werden Zeilen durch das Vorhandensein einer neuen Zeile bestimmt, sodass sie gelesen werden muss.

Verwenden Sie einen Stream, der readline unterstützt, und lesen Sie einfach die ersten X-1-Zeilen, geben Sie die Ergebnisse aus und verarbeiten Sie die nächste.

Uri
quelle
2

In Java 8

Für kleine Dateien:

String line = Files.readAllLines(Paths.get("file.txt")).get(n);

Für große Dateien:

String line;
try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) {
    line = lines.skip(n).findFirst().get();
}

In Java 7

String line;
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
    for (int i = 0; i < n; i++)
        br.readLine();
    line = br.readLine();
}

Quelle: Lesen der n-ten Zeile aus der Datei

Sid
quelle
1
public String readLine(int line){
        FileReader tempFileReader = null;
        BufferedReader tempBufferedReader = null;
        try { tempFileReader = new FileReader(textFile); 
        tempBufferedReader = new BufferedReader(tempFileReader);
        } catch (Exception e) { }
        String returnStr = "ERROR";
        for(int i = 0; i < line - 1; i++){
            try { tempBufferedReader.readLine(); } catch (Exception e) { }
        }
        try { returnStr = tempBufferedReader.readLine(); }  catch (Exception e) { }

        return returnStr;
    }
Cooper Scott
quelle
1

Es funktioniert für mich: Ich habe die Antwort Lesen einer einfachen Textdatei kombiniert

Aber anstatt einen String zurückzugeben, gebe ich eine LinkedList of Strings zurück. Dann kann ich die gewünschte Zeile auswählen.

public static LinkedList<String> readFromAssets(Context context, String filename) throws IOException {
    BufferedReader reader = new BufferedReader(new InputStreamReader(context.getAssets().open(filename)));
    LinkedList<String>linkedList = new LinkedList<>();
    // do reading, usually loop until end of file reading
    StringBuilder sb = new StringBuilder();
    String mLine = reader.readLine();
    while (mLine != null) {
        linkedList.add(mLine);
        sb.append(mLine); // process line
        mLine = reader.readLine();


    }
    reader.close();
    return linkedList;
}
Tachenko
quelle
Sie können dann tun: linkedlist.get (31)
Tachenko
1

Verwenden Sie diesen Code:

import java.nio.file.Files;

import java.nio.file.Paths;

public class FileWork 
{

    public static void main(String[] args) throws IOException {

        String line = Files.readAllLines(Paths.get("D:/abc.txt")).get(1);

        System.out.println(line);  
    }

}
Usman Yaqoob
quelle
0

Sie können LineNumberReader anstelle von BufferedReader verwenden. Geh durch die API. Sie finden die Methoden setLineNumber und getLineNumber.

Raghavendra
quelle
hilft nicht - Sie müssen noch alle Zeilen vorher lesen ... außer Sie betrügen und setzen die erste Zeile auf 32 <g>
kleopatra
0

Sie können sich auch LineNumberReader ansehen, die Unterklasse von BufferedReader. Neben der Readline-Methode gibt es auch Setter / Getter-Methoden für den Zugriff auf die Zeilennummer. Sehr nützlich, um die Anzahl der gelesenen Zeilen zu verfolgen, während Daten aus einer Datei gelesen werden.

Ankur Shanbhag
quelle
0

Mit der Funktion skip () können Sie die Zeilen von Anfang an überspringen.

public static void readFile(String filePath, long lineNum) {
    List<String> list = new ArrayList<>();
    long totalLines, startLine = 0;

    try (Stream<String> lines = Files.lines(Paths.get(filePath))) {
        totalLines = Files.lines(Paths.get(filePath)).count();
        startLine = totalLines - lineNum;
        // Stream<String> line32 = lines.skip(((startLine)+1));

        list = lines.skip(startLine).collect(Collectors.toList());
        // lines.forEach(list::add);
    } catch (IOException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }

    list.forEach(System.out::println);

}
Neelay Solanki
quelle
-7

Sie sind alle falsch. Ich habe das gerade in ungefähr 10 Sekunden geschrieben. Damit habe ich es geschafft, einfach die object.getQuestion ("Leinenzahl") in der Hauptmethode aufzurufen, um die gewünschte Zeile zurückzugeben.

public class Questions {

File file = new File("Question2Files/triviagame1.txt");

public Questions() {

}

public String getQuestion(int numLine) throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(file));
    String line = "";
    for(int i = 0; i < numLine; i++) {
        line = br.readLine();
    }
    return line; }}
user3526115
quelle