Java BufferedReader Class


In Java, reading large files efficiently is a common task, and the BufferedReader class plays a vital role in achieving that. It is part of the java.io package and is used to read text from input streams or files in an efficient manner. If you need to handle large files or perform line-by-line reading, BufferedReader is the perfect choice. In this blog, we will cover how to use the BufferedReader class, its key features, common use cases, and provide code examples for you to try out.


What is Java BufferedReader Class?

The BufferedReader class in Java is a wrapper around other input classes, such as FileReader, to provide buffering capabilities, allowing for more efficient reading of text from files or other sources. By using a buffer, it minimizes the number of reads to the underlying stream, improving performance significantly, especially when working with large files.

Key Features of BufferedReader:

  • Efficient Reading: It uses a buffer to read data in chunks, reducing the overhead of many read operations.
  • Line-by-Line Reading: It provides the readLine() method, which reads an entire line of text at once.
  • Supports Text Files: It works with text-based files such as .txt, .csv, and .xml.
  • Wrapper Class: It is commonly used with FileReader, InputStreamReader, or other input streams.

Syntax of BufferedReader Class

To use BufferedReader, you need to first create a BufferedReader object by passing an existing Reader object (like FileReader) to its constructor.

BufferedReader(Reader in)

For example, to create a BufferedReader with a FileReader:

BufferedReader br = new BufferedReader(new FileReader("example.txt"));

This creates a BufferedReader that reads from the file example.txt.


How to Use BufferedReader Class

The primary method of BufferedReader is readLine(), which allows you to read a file line by line. Let's look at a simple example.

Example 1: Reading a File Line by Line

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class BufferedReaderExample {
    public static void main(String[] args) {
        BufferedReader reader = null;

        try {
            // Create a FileReader and BufferedReader object
            reader = new BufferedReader(new FileReader("example.txt"));

            String line;
            // Read the file line by line
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // Close the BufferedReader
                if (reader != null) {
                    reader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Explanation:

  • We create a BufferedReader object, passing a FileReader that points to the example.txt file.
  • The readLine() method reads the file one line at a time, and the program prints each line to the console.
  • The finally block ensures that the BufferedReader is closed to release resources.

BufferedReader vs. FileReader

While both FileReader and BufferedReader can be used to read files in Java, they serve different purposes:

  • FileReader reads the file character by character, which can be slow for large files.
  • BufferedReader, on the other hand, reads large chunks of data at once into a buffer, improving performance when reading large files or multiple lines.

Example 2: Comparing FileReader and BufferedReader Performance

import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;

public class PerformanceComparison {
    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();

        // Using FileReader
        try (FileReader fr = new FileReader("largefile.txt")) {
            int i;
            while ((i = fr.read()) != -1) {
                // Reading byte by byte
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        long endTime = System.currentTimeMillis();
        System.out.println("FileReader time: " + (endTime - startTime) + " milliseconds");

        startTime = System.currentTimeMillis();

        // Using BufferedReader
        try (BufferedReader br = new BufferedReader(new FileReader("largefile.txt"))) {
            String line;
            while ((line = br.readLine()) != null) {
                // Reading line by line
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        endTime = System.currentTimeMillis();
        System.out.println("BufferedReader time: " + (endTime - startTime) + " milliseconds");
    }
}

Explanation:

  • This example compares the time taken to read a large file using FileReader (byte-by-byte reading) versus BufferedReader (line-by-line reading).
  • You'll likely see that BufferedReader is much faster due to its use of a buffer.

Other Useful Methods in BufferedReader

In addition to readLine(), BufferedReader provides several other useful methods:

  1. read(): Reads a single character. Similar to FileReader.read(), but buffered for efficiency.
  2. skip(long n): Skips n characters in the input stream.
  3. mark(int readAheadLimit): Marks the current position in the input stream so that you can later reset to it.
  4. reset(): Resets the stream to the position where mark() was last called.

Example 3: Using skip() and mark()

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class BufferedReaderAdvancedExample {
    public static void main(String[] args) {
        BufferedReader reader = null;

        try {
            // Create a BufferedReader to read the file
            reader = new BufferedReader(new FileReader("example.txt"));

            // Skip the first 10 characters
            reader.skip(10);

            // Mark the current position
            reader.mark(100);

            // Read the next line
            String line = reader.readLine();
            System.out.println("Line after skip: " + line);

            // Reset to the marked position
            reader.reset();
            line = reader.readLine();
            System.out.println("Line after reset: " + line);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // Close the BufferedReader
                if (reader != null) {
                    reader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Explanation:

  • The skip() method is used to skip the first 10 characters of the file.
  • We use the mark() method to mark the current position, and later call reset() to return to that position.

Exception Handling in BufferedReader

BufferedReader can throw IOException if there are issues with the underlying file or stream. It's important to handle these exceptions to ensure the program doesn't crash unexpectedly.

Example 4: Exception Handling with BufferedReader

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class BufferedReaderWithExceptionHandling {
    public static void main(String[] args) {
        BufferedReader reader = null;

        try {
            // Try reading from a non-existing file
            reader = new BufferedReader(new FileReader("nonexistentfile.txt"));
            String line = reader.readLine();
            System.out.println(line);
        } catch (IOException e) {
            System.out.println("An error occurred while reading the file: " + e.getMessage());
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (IOException e) {
                System.out.println("Error closing BufferedReader: " + e.getMessage());
            }
        }
    }
}

Explanation:

  • This example demonstrates how to handle IOException when attempting to read from a file that doesn't exist.
  • It ensures that the BufferedReader is properly closed, even if an error occurs.

Best Practices When Using BufferedReader

  1. Always Close Resources: Use the close() method in a finally block or try-with-resources to ensure the BufferedReader is closed after use.
  2. Use BufferedReader for Large Files: For large files, always use BufferedReader instead of FileReader to read more efficiently.
  3. Handle Exceptions: Always handle IOException to deal with potential file-related errors.
  4. Avoid Reading Character by Character: When possible, avoid using read() to read one character at a time, as it's slower compared to using readLine().