Back to Blog
Java

Java FileReader: How to Read Text Files

java filereader: Learn how to use Java FileReader to read character data from files, handle encoding, close resources, and improve performance with BufferedReader.

JavaFileReaderFile I/OCharacter StreamsBufferedReaderException Handling
Illustration of Java FileReader reading characters from a text file with a BufferedReader for efficiency.

The java filereader class is the simplest way to read character data from a file in Java. It treats the file as a stream of characters, decoding bytes according to the platform's default charset. This makes it convenient for small text files when you know the file encoding matches the runtime environment, but it also introduces a few pitfalls that can cause subtle bugs.

What FileReader Does and When to Use It

FileReader extends InputStreamReader and is specifically designed to read character files. It opens a FileInputStream internally and converts bytes to characters using the default charset of the JVM. Because of this, FileReader is best suited for files that use the same encoding as the platform, such as ASCII or UTF-8 on many modern systems.

You should use FileReader when:

  • You are reading a text file with a known, platform-compatible encoding.
  • You need a minimal API without extra configuration.
  • You are working with small files where buffering is not critical.

For anything else, especially files with a specific encoding or large files that need efficient reading, you should consider InputStreamReader with an explicit charset or wrap the stream in a BufferedReader.

Creating a FileReader and Reading Characters

The FileReader class provides three constructors:

ConstructorDescription
FileReader(String fileName)Opens the named file for reading.
FileReader(File file)Opens the file represented by the File object.
FileReader(FileDescriptor fd)Opens a file descriptor for reading.

The first two are the most common. The constructor throws FileNotFoundException if the file does not exist or cannot be opened.

Here is a minimal example that reads a single character:

import java.io.FileReader; import java.io.IOException; public class ReadSingleChar { public static void main(String[] args) { try (FileReader reader = new FileReader("example.txt")) { int charCode = reader.read(); if (charCode != -1) { System.out.println("First character: " + (char) charCode); } } catch (IOException e) { e.printStackTrace(); } } }

The read() method returns the character as an int value in the range 0 to 65535, or -1 if the end of the stream has been reached. Because it returns an int, you must cast it to char when you want to use the character value.

Reading one character at a time is inefficient for larger files. A better approach is to read into a character array:

char[] buffer = new char[1024]; int numCharsRead; while ((numCharsRead = reader.read(buffer)) != -1) { // process the characters in buffer[0..numCharsRead-1] }

This reduces the number of I/O operations and is more practical for processing file content in chunks.

Handling Character Encoding with FileReader

The biggest limitation of FileReader is that it uses the default charset of the JVM. If the file uses a different encoding, the characters will be decoded incorrectly. For example, a file saved as UTF-8 on a system where the default charset is ISO-8859-1 will produce garbled output for non-ASCII characters.

To control the encoding explicitly, use InputStreamReader with a FileInputStream:

import java.io.FileInputStream; import java.io.InputStreamReader; import java.io.Reader; import java.nio.charset.StandardCharsets; try (Reader reader = new InputStreamReader( new FileInputStream("example.txt"), StandardCharsets.UTF_8)) { // read characters }

This is the recommended approach when you need to guarantee a specific encoding. FileReader has no constructor that accepts a charset, so it cannot be used for this purpose.

If you are working with UTF-8 files, which is common in modern applications, you should almost always prefer InputStreamReader with StandardCharsets.UTF_8 over FileReader.

Using BufferedReader for Efficient Line Reading

FileReader itself does not buffer input. Each call to read() triggers a read from the underlying file, which can be expensive. For text files that are read line by line, the standard pattern is to wrap FileReader in a BufferedReader.

import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; try (BufferedReader br = new BufferedReader(new FileReader("example.txt"))) { String line; while ((line = br.readLine()) != null) { System.out.println(line); } }

BufferedReader provides a readLine() method that returns a line without the newline characters, or null when the end of the file is reached. The internal buffer reduces the number of underlying I/O calls, which improves performance for typical text processing.

You can also use BufferedReader with InputStreamReader to combine explicit encoding with buffering:

try (BufferedReader br = new BufferedReader( new InputStreamReader( new FileInputStream("example.txt"), StandardCharsets.UTF_8))) { String line; while ((line = br.readLine()) != null) { // process line } }

This is the most flexible and efficient approach for reading text files in Java.

Closing Resources and Handling Exceptions

FileReader, like all I/O classes, must be closed after use to release the underlying file handle. Failing to close a reader can lead to resource leaks and prevent other processes from accessing the file.

The modern way to handle this is the try-with-resources statement, which automatically closes the reader at the end of the block, even if an exception occurs.

try (FileReader reader = new FileReader("example.txt")) { // read data } catch (IOException e) { // handle I/O error }

If you are using a BufferedReader, closing it also closes the underlying FileReader, so you only need to close the outermost stream.

The constructor throws FileNotFoundException if the file is missing, and the read() methods throw IOException for I/O errors. Catching IOException covers both cases if you include the constructor inside the try block. However, if you need to distinguish a missing file from other errors, you can catch FileNotFoundException separately.

Common Mistakes and Compatibility Notes

One common mistake is assuming that FileReader uses UTF-8 by default. It does not; it uses the platform default, which varies across systems. This can cause data corruption when the file encoding differs.

Another mistake is using FileReader for binary files. FileReader is a character stream, so it decodes bytes into characters. For binary data, use FileInputStream directly.

FileReader has been part of Java since version 1.1, so compatibility is not a concern for modern applications. However, because it does not support explicit charsets, many developers consider it a legacy class and prefer InputStreamReader for new code.

Performance Considerations for Large Files

Reading a file with FileReader without buffering is inefficient because each read() call performs a native I/O operation. For large files, this can result in thousands of system calls and poor performance.

Using BufferedReader reduces the number of I/O operations by reading a large chunk of data into memory at once. The default buffer size is 8192 characters, which is adequate for most use cases. If you need to process very large files, you can also consider using Files.newBufferedReader from the java.nio.file package, which returns a BufferedReader with a configurable charset and buffer size.

import java.nio.file.Files; import java.nio.file.Path; import java.nio.charset.StandardCharsets; import java.io.BufferedReader; try (BufferedReader br = Files.newBufferedReader( Path.of("example.txt"), StandardCharsets.UTF_8)) { String line; while ((line = br.readLine()) != null) { // process line } }

This approach combines the convenience of a buffered reader with explicit encoding control and is the recommended method for reading text files in modern Java.

When you need to read the entire file into memory, Files.readString is even simpler, but it is only suitable for files that fit comfortably in memory.

java filereader: Practical Usage and Code Examples | RYUSLOG DEV