Java > Java Input/Output (I/O) > File Handling > BufferedReader and BufferedWriter

Reading and Writing Text Files with BufferedReader and BufferedWriter

This snippet demonstrates how to efficiently read and write text files using BufferedReader and BufferedWriter in Java. These classes provide buffered character streams, improving performance by minimizing the number of direct I/O operations.

Core Concepts

BufferedReader reads text from a character-input stream, buffering characters so as to provide for the efficient reading of characters, arrays, and lines. BufferedWriter writes text to a character-output stream, buffering characters so as to provide for the efficient writing of single characters, arrays, and strings. Buffering reduces the number of actual I/O operations to the underlying stream, which can significantly improve performance, especially when dealing with large files.

Reading from a File

This code reads each line from the file 'input.txt' using BufferedReader and prints it to the console. The try-with-resources statement ensures that the reader is automatically closed after use, even if an exception occurs.

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

public class BufferedReaderExample {

    public static void main(String[] args) {
        String filePath = "input.txt";

        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.err.println("Error reading file: " + e.getMessage());
        }
    }
}

Writing to a File

This code writes three lines of text to the file 'output.txt' using BufferedWriter. The flush() method is called to ensure that all buffered data is written to the file before the writer is closed. The try-with-resources statement ensures that the writer is automatically closed after use.

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class BufferedWriterExample {

    public static void main(String[] args) {
        String filePath = "output.txt";

        try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) {
            writer.write("This is the first line.\n");
            writer.write("This is the second line.\n");
            writer.write("This is the third line.\n");
            // Ensure all buffered data is written to the file
            writer.flush();
        } catch (IOException e) {
            System.err.println("Error writing to file: " + e.getMessage());
        }
    }
}

Real-Life Use Case

BufferedReader and BufferedWriter are commonly used in applications that process large text files, such as log analysis tools, data processing pipelines, and text editors. They are also useful for reading and writing configuration files, CSV files, and other text-based data formats.

Best Practices

  • Always use try-with-resources to ensure that the streams are closed properly, even if exceptions occur.
  • Use buffering for improved performance, especially when reading or writing large files.
  • Consider using flush() periodically to ensure that data is written to the file, especially when writing large amounts of data.
  • Handle IOException appropriately, logging errors or taking corrective actions.

Interview Tip

Be prepared to discuss the benefits of using buffered streams over unbuffered streams. Explain how buffering can improve performance by reducing the number of I/O operations. Also, be familiar with the try-with-resources statement and its advantages for resource management.

When to Use Them

Use BufferedReader and BufferedWriter when you need to read or write text files efficiently, especially when dealing with large files. They are also suitable for reading and writing data from other character-based streams, such as network sockets.

Memory Footprint

The memory footprint of BufferedReader and BufferedWriter depends on the buffer size. The default buffer size is typically 8KB. Larger buffer sizes can improve performance but also increase memory usage. Choose a buffer size that balances performance and memory usage.

Alternatives

  • Files.readAllLines() and Files.write() (Java NIO.2): These methods provide a simpler way to read and write entire files, but they may not be suitable for very large files.
  • Scanner: This class can be used to read formatted data from a file, but it is generally slower than BufferedReader.

Pros

  • Improved performance due to buffering.
  • Easy to use for reading and writing text files.
  • Automatic resource management with try-with-resources.

Cons

  • Requires handling IOException.
  • May not be suitable for binary files.

FAQ

  • What is the purpose of buffering in BufferedReader and BufferedWriter?

    Buffering reduces the number of direct I/O operations to the underlying stream, which can significantly improve performance, especially when dealing with large files.
  • Why use try-with-resources with BufferedReader and BufferedWriter?

    try-with-resources ensures that the streams are automatically closed after use, even if an exception occurs, preventing resource leaks.
  • When should I call flush() on a BufferedWriter?

    Call flush() periodically to ensure that data is written to the file, especially when writing large amounts of data or when you need to guarantee that the data is written to disk immediately.