Originally published at https://www.baeldung.com
As the name suggests, FileReader is a Java class that makes it easy to read the contents of a file.
In this tutorial, we'll learn the basic concept of a Reader and how we can use the FileReader class for doing read operations on a character stream in Java.
If we look at the code of the FileReader class, then we'll notice that the class contains minimal code for creating a FileReader object and no other methods.
This raises questions like “Who does the heavy lifting behind this class?”
To answer this question, we must understand the concept and hierarchy of the Reader class in Java.
Reader is an abstract base class that makes reading characters possible through one of its concrete implementations. It defines the following basic operations of reading characters from any medium such as memory or the filesystem:
Naturally, all the implementations of Reader class must implement all the abstract methods, namely read() and close(). Moreover, most implementations also override other inherited methods to give additional functionality or better performance.
Now that we've some understanding about a Reader, we're ready to bring our focus back to the FileReader class.
FileReader inherits its functionality from InputStreamReader, which is a Reader implementation designed to read bytes from an input stream as characters.
Let's see this hierarchy in the class definitions:
public class InputStreamReader extends Reader {} public class FileReader extends InputStreamReader {}
In general, we can use an InputStreamReader for reading characters from any input source.
However, when it comes to reading text from a file, using an InputStreamReader would be like cutting an apple with a sword. Of course, the right tool would be a knife, which is precisely what FileReader promises.
We can use a FileReader when we want to read text from a file using the system's default character set. For any other advanced functionality, it'd be ideal for making use of InputStreamReader class directly.
Let's walk through a coding exercise of reading characters from a HelloWorld.txt file using a FileReader instance.
As a convenience class, FileReader offers three overloaded constructors that can be used to initialize a reader that can read from a file as an input source.
Let's take a look at these constructors:
public FileReader(String fileName) throws FileNotFoundException { super(new FileInputStream(fileName)); } public FileReader(File file) throws FileNotFoundException { super(new FileInputStream(file)); } public FileReader(FileDescriptor fd) { super(new FileInputStream(fd)); }
In our case, we know the filename of the input file. Consequently, we can use the first constructor to initialize a reader:
FileReader fileReader = new FileReader(path);
Next, let's create readAllCharactersOneByOne(), a method for reading characters from the file one at a time:
public static String readAllCharactersOneByOne(Reader reader) throws IOException { StringBuilder content = new StringBuilder(); int nextChar; while ((nextChar = reader.read()) != -1) { content.append((char) nextChar); } return String.valueOf(content); }
As we can see from the above code, we've used the read() method in a loop to read characters one by one until it returns -1, meaning there're no more characters to read.
Now, let's test our code by validating that the text read from the file matches the expected text:
@Test public void givenFileReader_whenReadAllCharacters_thenReturnsContent() throws IOException { String expectedText = "Hello, World!"; File file = new File(FILE_PATH); try (FileReader fileReader = new FileReader(file)) { String content = FileReaderExample.readAllCharactersOneByOne(fileReader); Assert.assertEquals(expectedText, content); } }
We can even read multiple characters at once using the inherited read(char cbuf[], int off, int len) method:
public static String readMultipleCharacters(Reader reader, int length) throws IOException { char[] buffer = new char[length]; int charactersRead = reader.read(buffer, 0, length); if (charactersRead != -1) { return new String(buffer, 0, charactersRead); } else { return ""; } }
There's a subtle difference in the return value of read() when it comes to reading multiple characters in an array. The return value here is either the number of characters read or -1 if the reader has reached the end of the input stream.
Next, let's test the correctness of our code:
@Test public void givenFileReader_whenReadMultipleCharacters_thenReturnsContent() throws IOException { String expectedText = "Hello"; File file = new File(FILE_PATH); try (FileReader fileReader = new FileReader(file)) { String content = FileReaderExample.readMultipleCharacters(fileReader, 5); Assert.assertEquals(expectedText, content); } }
We've seen that the FileReader class relies on the default system character encoding.
So, for situations, where we need to use custom values for the character set, buffer size, or input stream, we must use InputStreamReader.
Moreover, we all know that I/O cycles are expensive and can introduce latency to our application. So, it's in our best interest to minimize the number of I/O operations by wrapping a BufferedReader around our FileReader object:
BufferedReader in = new BufferedReader(fileReader);
In this tutorial, we learned about the basic concepts of a Reader and how FileReader makes it simple to do read operations on text files though some examples.
As always, the complete source code for the tutorial is available on GitHub.
Thanks for reading ❤
If you liked this post, share it with all of your programming buddies!
Follow us on Facebook | Twitter
☞ Java Tutorial for Absolute Beginners
☞ 100+ Java Interview Questions and Answers In 2019
☞ Python vs Java: Understand Object Oriented Programming
☞ Angular 7 + Spring Boot CRUD Example
#java