Java > Java Input/Output (I/O) > File Handling > Reading and Writing Files with FileReader and FileWriter

Reading and Writing Files with FileReader and FileWriter in Java

This code snippet demonstrates how to read data from a text file and write data to another text file using FileReader and FileWriter classes in Java. These classes provide a simple way to handle character-based file I/O operations.

Code Snippet

The code reads from input.txt character by character using FileReader and writes each character to output.txt using FileWriter. The try-with-resources statement ensures that the reader and writer are closed automatically, even if an exception occurs.

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class FileReadWriteExample {

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

        try (FileReader reader = new FileReader(inputFile);
             FileWriter writer = new FileWriter(outputFile)) {

            int character;
            while ((character = reader.read()) != -1) {
                writer.write(character);
            }

            System.out.println("File copied successfully!");

        } catch (IOException e) {
            System.err.println("An error occurred: " + e.getMessage());
        }
    }
}

Concepts Behind the Snippet

  • FileReader: Used to read character streams from a file.
  • FileWriter: Used to write character streams to a file.
  • IOException: Checked exception that must be handled when performing file I/O operations.
  • try-with-resources: Ensures that resources are closed automatically after use. This is crucial to prevent resource leaks.
  • read(): Reads a single character from the input stream. It returns -1 when the end of the file is reached.
  • write(): Writes a single character to the output stream.

Real-Life Use Case

This approach is helpful in scenarios where you need to:

  • Duplicate a configuration file.
  • Convert a text file from one encoding to another.
  • Simple data transformation (e.g., replacing certain characters) during file copy.

Best Practices

  • Always handle IOException properly using try-catch blocks.
  • Use try-with-resources to automatically close readers and writers, preventing resource leaks.
  • For larger files or more complex processing, consider using buffered streams (BufferedReader and BufferedWriter) for improved performance.

Interview Tip

Be prepared to explain the difference between character streams (FileReader/FileWriter) and byte streams (FileInputStream/FileOutputStream). Also, be ready to discuss exception handling in file I/O and the importance of closing resources.

When to Use Them

Use FileReader and FileWriter when you need to read and write character-based data (text files). If you are dealing with binary data, use FileInputStream and FileOutputStream instead.

Memory Footprint

FileReader and FileWriter handle data character by character (or in small chunks). For very large files, consider using buffered streams to read and write data in larger blocks, which can reduce the number of I/O operations and improve performance. Also, the data is typically stored in memory one character at a time, making it suitable for handling larger files than those processed entirely into memory at once.

Alternatives

Alternatives to FileReader and FileWriter:

  • BufferedReader and BufferedWriter: Buffered character streams for improved performance.
  • FileInputStream and FileOutputStream: Byte streams for handling binary data.
  • Files.readAllLines and Files.write: Java NIO methods for reading and writing entire files with fewer lines of code. These are often preferred for simple operations.

Pros

  • Simple and straightforward for basic text file I/O.
  • Easy to understand and use.

Cons

  • Can be inefficient for large files due to character-by-character I/O.
  • Does not support binary data.

Another Code Snippet using BufferedReader/BufferedWriter

This improved version utilizes BufferedReader and BufferedWriter. Instead of reading a single character at a time, it reads an entire line. writer.newLine() ensures the lines are separated correctly in the output file.

The use of buffering significantly improves performance when dealing with larger files because it reduces the number of direct I/O operations to the disk.

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

public class BufferedFileReadWriteExample {

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

        try (BufferedReader reader = new BufferedReader(new FileReader(inputFile));
             BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile))) {

            String line;
            while ((line = reader.readLine()) != null) {
                writer.write(line);
                writer.newLine(); // Add a new line character
            }

            System.out.println("File copied successfully using buffered streams!");

        } catch (IOException e) {
            System.err.println("An error occurred: " + e.getMessage());
        }
    }
}

FAQ

  • What happens if the input file does not exist?

    An FileNotFoundException will be thrown. You should handle this exception in a try-catch block to gracefully handle the missing file.
  • How do I append to an existing file instead of overwriting it?

    When creating the FileWriter, pass true as the second argument to the constructor, e.g., FileWriter writer = new FileWriter(outputFile, true). This will open the file in append mode.
  • What is the difference between FileReader/FileWriter and FileInputStream/FileOutputStream?

    FileReader and FileWriter are used for character streams (text files), while FileInputStream and FileOutputStream are used for byte streams (binary files). Choose the appropriate class based on the type of data you are working with.
  • Why use try-with-resources?

    The try-with-resources statement automatically closes the resources (FileReader and FileWriter in this case) when the try block completes, whether normally or due to an exception. This prevents resource leaks and simplifies code.