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.
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=newFileInputStream("someFile.txt");BufferedReader br =newBufferedReader(newInputStreamReader(fs));for(int i =0; i <31;++i)
br.readLine();String lineIWant = br.readLine();
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.
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.
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 RandomAccessFileRandomAccessFile raf =newRandomAccessFile("myFile.txt","r");//above 'r' means open in read only modeArrayList<Integer> arrayList =newArrayList<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();
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.
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);}
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.
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.
Aber anstatt einen String zurückzugeben, gebe ich eine LinkedList of Strings zurück. Dann kann ich die gewünschte Zeile auswählen.
publicstaticLinkedList<String> readFromAssets(Context context,String filename)throwsIOException{BufferedReader reader =newBufferedReader(newInputStreamReader(context.getAssets().open(filename)));LinkedList<String>linkedList =newLinkedList<>();// do reading, usually loop until end of file readingStringBuilder sb =newStringBuilder();String mLine = reader.readLine();while(mLine !=null){
linkedList.add(mLine);
sb.append(mLine);// process line
mLine = reader.readLine();}
reader.close();return linkedList;}
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.
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.
publicclassQuestions{File file =newFile("Question2Files/triviagame1.txt");publicQuestions(){}publicString getQuestion(int numLine)throwsIOException{BufferedReader br =newBufferedReader(newFileReader(file));String line ="";for(int i =0; i < numLine; i++){
line = br.readLine();}return line;}}
Antworten:
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.
quelle
Für kleine Dateien:
Für große Dateien:
quelle
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
quelle
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:
http://commons.apache.org/io/api-release/org/apache/commons/io/FileUtils.html#readLines(java.io.File , java.lang.String)
quelle
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:
Im obigen Beispiel wird eine Textdatei gelesen, die aus 50 Zeilen im folgenden Format besteht:
Disclamer: Ich habe diese Bibliothek geschrieben
quelle
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.
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 !
quelle
Ein anderer Weg.
quelle
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.
quelle
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.
quelle
In Java 8
Für kleine Dateien:
Für große Dateien:
In Java 7
Quelle: Lesen der n-ten Zeile aus der Datei
quelle
quelle
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.
quelle
Verwenden Sie diesen Code:
quelle
Sie können LineNumberReader anstelle von BufferedReader verwenden. Geh durch die API. Sie finden die Methoden setLineNumber und getLineNumber.
quelle
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.
quelle
Mit der Funktion skip () können Sie die Zeilen von Anfang an überspringen.
quelle
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.
quelle