Java Top

The early-bird price of the new Learn Spring Security OAuth course packages will increase by $50 on Wednesday:

>> CHECK OUT THE COURSE

1. Overview

In this tutorial, we’ll learn how to find the number of lines in a file using Java with the help of standard Java IO APIs, Google Guava and the Apache Commons IO library.

2. NIO2 Files

Note that, across this tutorial, we'll be using the following sample values as the input file name and the total number of lines:

static final String INPUT_FILE_NAME = "src/main/resources/input.txt";
static final int NO_OF_LINES = 45;

Java 7 introduced many improvements to the existing IO libraries and packaged it under NIO2:

Let's start with Files and see how can we use its API to count the numbers of lines:

@Test
public void whenUsingNIOFiles_thenReturnTotalNumberOfLines() throws IOException {
    try (Stream<String> fileStream = Files.lines(Paths.get(INPUT_FILE_NAME))) {
        int noOfLines = (int) fileStream.count();
        assertEquals(NO_OF_LINES, noOfLines);
    }
}

Or by simply using Files#readAllLines method:

@Test
public void whenUsingNIOFilesReadAllLines_thenReturnTotalNumberOfLines() throws IOException {
    List<String> fileStream = Files.readAllLines(Paths.get(INPUT_FILE_NAME));
    int noOfLines = fileStream.size();
    assertEquals(NO_OF_LINES, noOfLines);
}

3. NIO FileChannel

Now let's check FileChannel, a high-performance Java NIO alternative to read the number of lines:

@Test
public void whenUsingNIOFileChannel_thenReturnTotalNumberOfLines() throws IOException {
    int noOfLines = 1;
    try (FileChannel channel = FileChannel.open(Paths.get(INPUT_FILE_NAME), StandardOpenOption.READ)) {
        ByteBuffer byteBuffer = channel.map(MapMode.READ_ONLY, 0, channel.size());
        while (byteBuffer.hasRemaining()) {
            byte currentByte = byteBuffer.get();
            if (currentByte == '\n')
                noOfLines++;
       }
    }
    assertEquals(NO_OF_LINES, noOfLines);
}

Though the FileChannel was introduced in JDK 4, the above solution works only with JDK 7 or higher.

4. Google Guava Files

An alternative third-party library would be Google Guava Files class. This class can also be used to count the total number of lines in a similar way to what we saw with Files#readAllLines.

Let’s start by adding the guava dependency in our pom.xml:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>28.0-jre</version>
</dependency>

And then we can use readLines to get a List of file lines:

@Test
public void whenUsingGoogleGuava_thenReturnTotalNumberOfLines() throws IOException {
    List<String> lineItems = Files.readLines(Paths.get(INPUT_FILE_NAME)
      .toFile(), Charset.defaultCharset());
    int noOfLines = lineItems.size();
    assertEquals(NO_OF_LINES, noOfLines);
}

5. Apache Commons IO FileUtils

Now, let's see Apache Commons IO FileUtils API, a parallel solution to Guava.

To use the library, we have to include the commons-io dependency in the pom.xml:

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>

At that point, we can use Apache Commons IO's FileUtils#lineIterator, which cleans up some of the file handlings for us:

@Test
public void whenUsingApacheCommonsIO_thenReturnTotalNumberOfLines() throws IOException {
    int noOfLines = 0;
    LineIterator lineIterator = FileUtils.lineIterator(new File(INPUT_FILE_NAME));
    while (lineIterator.hasNext()) {
        lineIterator.nextLine();
        noOfLines++;
    }
    assertEquals(NO_OF_LINES, noOfLines);
}

As we can see, this is a bit more verbose than the Google Guava solution.

6. BufferedReader

So, what about old-school ways? If we aren't on JDK 7 and we can't use a third-party library, we have BufferedReader:

@Test
public void whenUsingBufferedReader_thenReturnTotalNumberOfLines() throws IOException {
    int noOfLines = 0;
    try (BufferedReader reader = new BufferedReader(new FileReader(INPUT_FILE_NAME))) {
        while (reader.readLine() != null) {
            noOfLines++;
        }
    }
    assertEquals(NO_OF_LINES, noOfLines);
}

7. LineNumberReader

Or, we can use LineNumberReader, a direct subclass of BufferedReader, which is just a bit less verbose:

@Test
public void whenUsingLineNumberReader_thenReturnTotalNumberOfLines() throws IOException {
    try (LineNumberReader reader = new LineNumberReader(new FileReader(INPUT_FILE_NAME))) {
        reader.skip(Integer.MAX_VALUE);
        int noOfLines = reader.getLineNumber() + 1;
        assertEquals(NO_OF_LINES, noOfLines);
    }
}

Here we are calling the skip method to go to the end of the file, and we're adding 1 to the total number of lines counted since the line numbering begins at 0.

8. Scanner

And finally, if we're already using Scanner as part of a larger solution, it can solve the problem for us, too:

@Test
public void whenUsingScanner_thenReturnTotalNumberOfLines() throws IOException {
    try (Scanner scanner = new Scanner(new FileReader(INPUT_FILE_NAME))) {
        int noOfLines = 0;
        while (scanner.hasNextLine()) {
            scanner.nextLine();
            noOfLines++;
        }
        assertEquals(NO_OF_LINES, noOfLines);
    }
}

9. Conclusion

In this tutorial, we have explored different ways to find the number of lines in a file using Java. Since the main purpose of all these APIs is not for counting the number of lines in a file, it's recommended choosing the right solution for our need.

As always, the source code for this tutorial is available over on GitHub.

Java bottom

The early-bird price of the new Learn Spring Security OAuth course packages will increase by $50 on Wednesday:

>> CHECK OUT THE COURSE
Comments are closed on this article!