Bagaimana cara membaca baris tertentu menggunakan nomor baris tertentu dari file di Java?

91

Di Java, apakah ada metode untuk membaca baris tertentu dari file? Misalnya, baca baris 32 atau nomor baris lainnya.

Trinitas
sumber
5
Saya tahu saya sangat terlambat, tetapi jika seseorang menemukan pertanyaan ini: Perhatikan bahwa file hanyalah urutan byte. Dan baris baru hanyalah satu karakter (dua di Windows), dan karakter hanya satu (atau lebih, tergantung pada pengkodean) byte. Dan, tanpa memiliki indeks posisi byte dalam file, satu-satunya cara untuk mengetahui di mana byte tersebut berada adalah dengan membacanya dan mencarinya. (ini tidak berarti bahwa Anda harus memuat seluruh file ke dalam memori).
szgal

Jawaban:

72

Kecuali Anda memiliki pengetahuan sebelumnya tentang baris di file, tidak ada cara untuk langsung mengakses baris ke-32 tanpa membaca 31 baris sebelumnya.

Itu benar untuk semua bahasa dan semua sistem file modern.

Jadi secara efektif Anda hanya akan membaca baris sampai Anda menemukan baris ke-32.

Joachim Sauer
sumber
4
"Pengetahuan sebelumnya" bisa sesederhana pola ukuran baris yang tepat dalam file sehingga Anda dapat mencari posisi tertentu.
Murali VP
2
@ Murali: tentu saja. Ini juga bisa menjadi indeks ofset nomor baris ke byte atau kombinasinya.
Joachim Sauer
104

Untuk file kecil:

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

Untuk file besar:

try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) {
    line32 = lines.skip(31).findFirst().get();
}
aioobe
sumber
Ini mengembalikan java.nio.charset.MalformedInputException: Panjang input = 1 saat digunakan dengan nilai lewati 1
canadiancreed
Itu bukan masalah dengan kode yang saya posting, ini masalah dengan pengkodean file Anda. Lihat posting ini .
aioobe
4
"Perhatikan bahwa metode ini ditujukan untuk kasus sederhana yang nyaman untuk membaca semua baris dalam satu operasi. Metode ini tidak dimaksudkan untuk membaca dalam file besar." - Javadoc of Files.readAllLines ()
PragmaticProgrammer
Kode berikut membutuhkan API level 26 di android. Jika min kami kurang dari level ini maka itu tidak berfungsi
Ali Azaz Alam
38

Bukan yang saya tahu, tetapi yang dapat Anda lakukan adalah melakukan loop melalui 31 baris pertama tanpa melakukan apa pun menggunakan fungsi readline () dari BufferedReader

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
sumber
1
Harap dicatat bahwa di sini Anda membaca nomor baris 30, yang merupakan baris ke-31 karena kita memulai nomor baris dari 0. Jadi saya sarankan untuk mengubahnya agar cocok dengan pertanyaannya.
kiedysktos
15

Joachim benar, tentu saja, dan implementasi alternatif untuk Chris '(untuk file kecil hanya karena memuat seluruh file) mungkin menggunakan commons-io dari Apache (meskipun Anda mungkin tidak ingin memperkenalkan dependensi baru hanya untuk ini, jika Anda merasa berguna untuk hal lain juga, itu bisa masuk akal).

Sebagai contoh:

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
sumber
2
Meskipun itu akan memuat seluruh file ke dalam memori sebelum pergi ke baris ke-32, yang mungkin tidak praktis dengan file besar dan akan lebih lambat daripada membaca dengan menemukan baris ke-32 ...
beny23
Poin yang adil, ya. Saya telah menggunakan itu dalam kasus uji, di mana file pengujian kecil, pada file besar, setuju, bukan pendekatan yang baik.
Charlie Collins
Posting jawaban yang diperbarui untuk mencerminkan bahwa FileUtils adalah ide buruk dalam kasus penggunaan ini jika Anda memiliki file besar dan tidak memerlukan apa pun di luar baris X.
Charlie Collins
11

Anda dapat mencoba indexed-file-reader (Apache License 2.0). Kelas IndexedFileReader memiliki metode yang disebut readLines (int from, int to) yang mengembalikan SortedMap yang kuncinya adalah nomor baris dan nilainya adalah baris yang telah dibaca.

Contoh:

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]"));      

Contoh di atas membaca file teks yang terdiri dari 50 baris dalam format berikut:

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

Penolakan: Saya menulis perpustakaan ini

jramoyo
sumber
6

Meskipun seperti yang dikatakan dalam jawaban lain, tidak mungkin untuk sampai ke baris yang tepat tanpa mengetahui offset (penunjuk) sebelumnya. Jadi, saya telah mencapai ini dengan membuat file indeks sementara yang akan menyimpan nilai offset setiap baris. Jika file cukup kecil, Anda bisa menyimpan indeks (offset) di memori tanpa memerlukan file terpisah untuk itu.

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

Kunjungi juga dokumen java untuk informasi lebih lanjut: https://docs.oracle.com/javase/8/docs/api/java/io/RandomAccessFile.html#mode

Kompleksitas : Ini adalah O (n) karena membaca seluruh file sekali. Harap perhatikan persyaratan memori. Jika terlalu besar untuk disimpan di memori, buat file sementara yang menyimpan offset, bukan ArrayList seperti yang ditunjukkan di atas.

Catatan : Jika semua yang Anda inginkan di baris '32', Anda hanya perlu memanggil readLine () yang juga tersedia melalui kelas lain '32' kali. Pendekatan di atas berguna jika Anda ingin mendapatkan baris tertentu (tentu saja berdasarkan nomor baris) beberapa kali.

Terima kasih!

ShankarDaruga
sumber
Ada sesuatu yang perlu diedit untuk membuat kode di atas berfungsi. Dan jika seseorang membutuhkan charset yang bersangkutan, Anda benar-benar harus membaca ini: stackoverflow.com/a/37275357/3198960
rufushuang
5

Cara lain.

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
sumber
1
Elegan, saya menyukainya.
Florescu Cătălin
4

Tidak, kecuali dalam format file itu panjang baris sudah ditentukan sebelumnya (misalnya semua baris dengan panjang tetap), Anda harus mengulang baris demi baris untuk menghitungnya.

kaldu
sumber
2

Jika Anda berbicara tentang file teks, maka tidak ada cara untuk melakukan ini tanpa membaca semua baris yang mendahuluinya - Bagaimanapun, baris ditentukan oleh keberadaan baris baru, jadi itu harus dibaca.

Gunakan aliran yang mendukung garis baca, dan cukup baca baris X-1 pertama dan buang hasilnya, lalu proses baris berikutnya.

Uri
sumber
2

Di Jawa 8,

Untuk file kecil:

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

Untuk file besar:

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

Di Jawa 7

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

Sumber: Membaca baris ke-n dari file

Sid
sumber
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
sumber
1

Ini bekerja untuk saya: Saya telah menggabungkan jawaban Membaca file teks sederhana

Tapi bukannya mengembalikan String saya mengembalikan LinkedList of Strings. Kemudian saya dapat memilih jalur yang saya inginkan.

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
sumber
Anda kemudian dapat melakukan: linkedlist.get (31)
Tachenko
1

Gunakan kode ini:

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
sumber
0

Anda dapat menggunakan LineNumberReader sebagai ganti BufferedReader. Pergi melalui api. Anda dapat menemukan metode setLineNumber dan getLineNumber.

Raghavendra
sumber
tidak membantu - Anda masih harus membaca semua baris sebelumnya ... kecuali Anda menipu dan menyetel baris pertama ke 32 <g>
kleopatra
0

Anda juga dapat melihat LineNumberReader, subkelas BufferedReader. Seiring dengan metode readline, ia juga memiliki metode penyetel / pengambil untuk mengakses nomor baris. Sangat berguna untuk melacak jumlah baris yang dibaca, saat membaca data dari file.

Ankur Shanbhag
sumber
0

Anda dapat menggunakan fungsi skip () untuk melewati baris dari awal.

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
sumber
0

CARA MUDAH - Membaca baris menggunakan nomor baris. Misalkan nomor baris dimulai dari 1 sampai null.

public class TextFileAssignmentOct {
    
    private void readData(int rowNum, BufferedReader br) throws IOException {
        int n=1;                                    //Line number starts from 1
        String row;
        while((row=br.readLine()) != null)  {       // Reads every line
            if (n == rowNum) {                      // When Line number matches with which you want to read
                System.out.println(row);
            }
            n++;                                    //This increments Line number
        }
    }

    public static void main(String[] args) throws IOException {
        File f = new File("../JavaPractice/FileRead.txt");
        FileReader fr = new FileReader(f);
        BufferedReader br = new BufferedReader(fr);
        
        TextFileAssignmentOct txf = new TextFileAssignmentOct();
        txf.readData(4, br);    //Read a Specific Line using Line number and Passing buffered reader
    }
}
Amit Verma
sumber
-7

Semuanya salah. Saya baru saja menulis ini dalam waktu sekitar 10 detik. Dengan ini saya berhasil memanggil object.getQuestion ("linenumber") dalam metode utama untuk mengembalikan baris apa pun yang saya inginkan.

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; }}
pengguna3526115
sumber