1. Overview

In this quick article, we’re going to look at different ways of reading a line at a given line number inside a file.

2. Input File

Let’s start by creating a simple file named inputLines.txt that we’ll use in all of our examples:

Line 1
Line 2
Line 3
Line 4
Line 5

3. Using BufferedReader

Let’s look at the well known BufferedReader class and its advantage of not storing the entire file into memory.

We can read a file line by line and stop when we desire:

@Test
public void givenFile_whenUsingBufferedReader_thenExtractedLineIsCorrect() {
    try (BufferedReader br = Files.newBufferedReader(Paths.get(FILE_PATH))) {
        for (int i = 0; i < 3; i++) {
            br.readLine();
        }

        String extractedLine = br.readLine();
        assertEquals("Line 4", extractedLine);
    }
}

4. Using Scanner

Another similar approach we can take is using a Scanner:

@Test
public void givenFile_whenUsingScanner_thenExtractedLineIsCorrect() {
    try (Scanner scanner = new Scanner(new File(FILE_PATH))) {
        for (int i = 0; i < 3; i++) {
            scanner.nextLine();
        }

        String extractedLine = scanner.nextLine();
        assertEquals("Line 4", extractedLine);
    }
}

Although on small files, the difference between BufferedReader and Scanner might not be noticeable, on larger files, the Scanner will be slower since it also does parsing and has a smaller buffer size.

5. Using the File API

5.1. Small Files

We can use Files.readAllLines() from the File API to easily read the contents of a file into memory and extract the line we desire:

@Test
public void givenSmallFile_whenUsingFilesAPI_thenExtractedLineIsCorrect() {
    String extractedLine = Files.readAllLines(Paths.get(FILE_PATH)).get(4);

    assertEquals("Line 5", extractedLine);
}

5.2. Large Files

If we need to work with large files, we should use the lines method, which returns a Stream so that we can read the file line by line:

@Test
public void givenLargeFile_whenUsingFilesAPI_thenExtractedLineIsCorrect() {
    try (Stream lines = Files.lines(Paths.get(FILE_PATH))) {
        String extractedLine = lines.skip(4).findFirst().get();

        assertEquals("Line 5", extractedLine);
    }
}

6. Using Apache Commons IO

Another option is using the FileUtils class of the commons-io package, which reads the whole file and returns the lines as a list of Strings:

@Test
public void givenFile_whenUsingFileUtils_thenExtractedLineIsCorrect() {
    ClassLoader classLoader = getClass().getClassLoader();
    File file = new File(classLoader.getResource("linesInput.txt").getFile());

    List<String> lines = FileUtils.readLines(file, "UTF-8");

    String extractedLine = lines.get(0);
    assertEquals("Line 1", extractedLine);
}

We can also use the IOUtils class to achieve the same result, except this time, the whole content is returned as a String, and we have to do the splitting ourselves:

@Test
public void givenFile_whenUsingIOUtils_thenExtractedLineIsCorrect() {
    String fileContent = IOUtils.toString(new FileInputStream(FILE_PATH), StandardCharsets.UTF_8);

    String extractedLine = fileContent.split(System.lineSeparator())[0];
    assertEquals("Line 1", extractedLine);
}

7. Conclusion

In this quick article, we’ve gone over the most common ways of reading a line at a given line number from a file.

As usual, the examples are available over on GitHub.