How to read a specific line using the specific line number from a file in Java?
Asked Answered
F

19

105

In Java, is there any method to read a particular line from a file? For example, read line 32 or any other line number.

Fou answered 22/2, 2010 at 17:30 Comment(1)
I know I am very late, but in case someone found this question: Note that a file is just a sequence of bytes. And a newline is just a character(two on Windows), and a character is just one(or more, depending on the encoding) byte. And, without having an index of the positions of a byte in a file, the only way to know where those bytes are is to read it and look for it. (this doesn't mean that you have to load the whole file into memory though).Togoland
C
81

Unless you have previous knowledge about the lines in the file, there's no way to directly access the 32nd line without reading the 31 previous lines.

That's true for all languages and all modern file systems.

So effectively you'll simply read lines until you've found the 32nd one.

Cheyennecheyne answered 22/2, 2010 at 17:32 Comment(2)
The "previous knowledge" can be as simple as exact line size pattern in the file so you can seek to a certain position.Simba
@Murali: of course. It could also be an index of line number to byte offset or any combination thereof.Cheyennecheyne
V
125

For small files:

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

For large files:

try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) {
    line32 = lines.skip(31).findFirst().get();
}
Volunteer answered 14/4, 2015 at 21:8 Comment(4)
This returns java.nio.charset.MalformedInputException: Input length = 1 when used with skip value being 1Dublin
That's not an issue with the code I posted, it's an issue with the encoding of your file. See this post.Volunteer
"Note that this method is intended for simple cases where it is convenient to read all lines in a single operation. It is not intended for reading in large files." - Javadoc of Files.readAllLines()Spragens
The following code requires API level 26 in android. If our min is less then this level then it don't workSacco
C
81

Unless you have previous knowledge about the lines in the file, there's no way to directly access the 32nd line without reading the 31 previous lines.

That's true for all languages and all modern file systems.

So effectively you'll simply read lines until you've found the 32nd one.

Cheyennecheyne answered 22/2, 2010 at 17:32 Comment(2)
The "previous knowledge" can be as simple as exact line size pattern in the file so you can seek to a certain position.Simba
@Murali: of course. It could also be an index of line number to byte offset or any combination thereof.Cheyennecheyne
L
40

Not that I know of, but what you could do is loop through the first 31 lines doing nothing using the readline() function of 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();
Lizbeth answered 22/2, 2010 at 17:35 Comment(1)
Please note that here you read line number 30, which is 31st line because we start line numbers from 0. So I would suggest changing it to match the question precisely.Disquisition
I
15

Joachim is right on, of course, and an alternate implementation to Chris' (for small files only because it loads the entire file) might be to use commons-io from Apache (though arguably you might not want to introduce a new dependency just for this, if you find it useful for other stuff too though, it could make sense).

For example:

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)

Iridium answered 22/2, 2010 at 21:45 Comment(3)
Though that would load the whole file into memory before going to the 32nd line, which might not be practical with a large file and would be slower than reading util finding the 32nd line...Anyaanyah
Fair point, yes. I have used that in test cases, where the testing files were small, on large files though, agreed, not a good approach.Iridium
Updated answer post to reflect that FileUtils is a bad idea in this use case if you have a large file and don't need anything beyond line X.Iridium
Z
12

You may try indexed-file-reader (Apache License 2.0). The class IndexedFileReader has a method called readLines(int from, int to) which returns a SortedMap whose key is the line number and the value is the line that was read.

Example:

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

The above example reads a text file composed of 50 lines in the following format:

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

Disclamer: I wrote this library

Zeena answered 22/5, 2013 at 5:27 Comment(0)
S
9

Although as said in other answers, it is not possible to get to the exact line without knowing the offset (pointer) before. So, I've achieved this by creating an temporary index file which would store the offset values of every line. If the file is small enough, you could just store the indexes (offset) in memory without needing a separate file for it.

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

Also visit the Java docs on RandomAccessFile for more information:

Complexity: This is O(n) as it reads the entire file once. Please be aware for the memory requirements. If it's too big to be in memory, then make a temporary file that stores the offsets instead of ArrayList as shown above.

Note: If all you want in '32' line, you just have to call the readLine() also available through other classes '32' times. The above approach is useful if you want to get the a specific line (based on line number of course) multiple times.

Sarong answered 6/9, 2017 at 11:39 Comment(3)
There is something need edit to make the above code work. And if someone need charset concerned, u really should read this: https://mcmap.net/q/205656/-how-to-read-utf8-encoded-file-using-randomaccessfileLayne
This is what I was looking for! To make the answer complete, I'd add a strategy for reading from the index file because if I need to re-read the index file each time I need a line, it sort of defies the purpose. So if I first write the byte offset for every line as a long (8bytes) in an index file. I can retrieve line 32 on the original by calculating the offset on the index file by doing 8*32, read the offset for the line on the original file and then use that to read from the original file itself. I'm going to try it out, hope it works.Armijo
Just un update on this tactic. It works but reading from a RandomAccessFile is super slow. Even Buffered implementations don't really cut it for a demanding application. For me, the fastest solution was to split the large file in pieces and then use an LRU cache. "Caffeine" is a great library for caching: github.com/ben-manes/caffeineArmijo
F
7

Another way.

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);
}
Flotilla answered 12/12, 2016 at 16:48 Comment(1)
Elegant, i like it.Authorize
A
4

No, unless in that file format the line lengths are pre-determined (e.g. all lines with a fixed length), you'll have to iterate line by line to count them.

Assumption answered 22/2, 2010 at 17:50 Comment(0)
T
4

In Java 8,

For small files:

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

For large files:

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

Source: Reading nth line from file

Thief answered 22/2, 2018 at 8:15 Comment(0)
I
2

If you are talking about a text file, then there is really no way to do this without reading all the lines that precede it - After all, lines are determined by the presence of a newline, so it has to be read.

Use a stream that supports readline, and just read the first X-1 lines and dump the results, then process the next one.

Intumescence answered 22/2, 2010 at 17:33 Comment(0)
E
1

It works for me: I have combined the answer of Reading a simple text file

But instead of return a String I am returning a LinkedList of Strings. Then I can select the line that I want.

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;
}
Extravasate answered 6/7, 2016 at 16:59 Comment(1)
You can then do: linkedlist.get(31)Extravasate
C
1

Use this 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);  
    }

}
Calvano answered 5/1, 2018 at 20:43 Comment(0)
T
0

You can use LineNumberReader instead of BufferedReader. Go through the api. You can find setLineNumber and getLineNumber methods.

Theall answered 17/1, 2012 at 9:46 Comment(1)
doesn't help - you still have to read all the lines before ... except you cheat and set the first line to 32 <g>Larkin
A
0

You can also take a look at LineNumberReader, subclass of BufferedReader. Along with the readline method, it also has setter/getter methods to access line number. Very useful to keep track of the number of lines read, while reading data from file.

Aragon answered 16/1, 2013 at 13:54 Comment(0)
S
0
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;
    }
Shadrach answered 3/10, 2015 at 4:46 Comment(0)
S
0

you can use the skip() function to skip the lines from begining.

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

}
Skinned answered 25/3, 2017 at 12:30 Comment(0)
R
0

EASY WAY - Reading a line using line number. Let's say Line number starts from 1 till 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
    }
}
Reichard answered 14/10, 2020 at 8:5 Comment(0)
L
0

for a text file you can use an integer with a loop to help you get the number of the line, don't forget to import the classes we are using in this example

    File myObj = new File("C:\\Users\\LENOVO\\Desktop\\test.txt");//path of the file
    FileReader fr = new FileReader(myObj);
    fr.read();
    
    BufferedReader bf = new BufferedReader(fr); //BufferedReader of the FileReader fr
    
    String line = bf.readLine();
    int lineNumber = 0;
    while (line != null) {
        lineNumber = lineNumber + 1;
        if(lineNumber == 7)
        {
            //show line
            System.out.println("line: " + lineNumber + " has :" + line);
            break;
        }
        //lecture de la prochaine ligne, reading next 
        line = bf.readLine();
    }
Learn answered 8/12, 2022 at 17:12 Comment(0)
F
-9

They are all wrong I just wrote this in about 10 seconds. With this I managed to just call the object.getQuestion("linenumber") in the main method to return whatever line I want.

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; }}
Finbur answered 12/4, 2014 at 6:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.