By WebNest Studio Engineering Team
Java - Core Tutorial
File Handling: File, FileReader, FileWriter, BufferedReader
Java's I/O classes let a program interact with the file system: checking whether files exist, creating or deleting them, and reading or writing their content. The classes are layered — some represent the file itself as metadata, while others actually stream bytes or characters into and out of that file.
Why it matters
Saving data to a file and reading it back is among the first practical things a program needs: exporting a report, keeping a log, importing a list. This lesson is the complete basic cycle of create, write, read and delete, and the try-with-resources habit it teaches applies to every resource you will ever open.
The File Class — Metadata, Not Content
java.io.File represents a path on the file system and lets you query or manipulate it without reading its contents: exists() checks if the path is present, mkdir()/mkdirs() create a directory (or the full directory chain), createNewFile() creates an empty file, and delete() removes a file or empty directory. A File object can represent a path that does not exist yet — creating the object does not touch the disk.
FileReader and FileWriter — Character Streams
FileReader and FileWriter are character streams: they read and write text one character (or char buffer) at a time, handling the platform's default character encoding. They are low-level and inefficient for line-based work on their own — every call to read() can involve a system call — which is why they are almost always wrapped by a buffering class.
BufferedReader — Efficient Line Reading
Wrapping a FileReader in a BufferedReader adds an internal buffer, dramatically reducing the number of actual disk reads, and adds the convenient readLine() method, which returns one line of text at a time and returns null when the end of the file is reached — the standard pattern for reading a text file line by line.
try-with-resources for Automatic Closing
Every stream class in java.io implements Closeable, and forgetting to close a stream leaks file handles. The try-with-resources statement, try (Resource r = ...) { ... }, automatically calls close() on each declared resource when the block exits, whether normally or via an exception, which is far safer than a manual finally block.
Example
Writing with FileWriter and reading it back line by line with BufferedReader
import java.io.File;
import java.io.FileWriter;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;
public class FileHandlingDemo {
public static void main(String[] args) throws IOException {
File file = new File("notes.txt");
System.out.println("Exists before write: " + file.exists());
try (FileWriter writer = new FileWriter(file)) {
writer.write("Line one\n");
writer.write("Line two\n");
}
System.out.println("Exists after write: " + file.exists());
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println("Read: " + line);
}
}
file.delete();
System.out.println("Exists after delete: " + file.exists());
}
}
Exists before write: false
Exists after write: true
Read: Line one
Read: Line two
Exists after delete: false
Common Mistakes
- Reading a file with plain FileReader.read() character-by-character in a loop instead of wrapping it in a BufferedReader — this works but performs far more I/O calls than necessary.
- Forgetting to close a FileWriter/FileReader in a finally block or try-with-resources, which can leave file handles open or leave written data unflushed to disk.
- Assuming new File("path") creates the file on disk — constructing a File object is purely in-memory; you must explicitly call createNewFile() or write to it.
- Checking readLine() for an empty string ("") instead of null to detect end-of-file — an empty string represents a genuinely blank line, not the end of the stream.
Exercise
Write two lines to a temporary file, read the file back line by line printing each line, and then print how many lines were read. Delete the file at the end.
Expected output: first, second, 2 (one per line)
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class WriteThenRead {
public static void main(String[] args) throws IOException {
File file = File.createTempFile("notes", ".txt");
// TODO: write "first" and "second" on separate lines
// TODO: read the file line by line, printing each line and counting them
// TODO: print the count
file.delete();
}
}
Show hints
- Wrap a
FileWriterin aBufferedWriterand callnewLine()after each line. - Open the writer and the reader in separate try-with-resources blocks, so the file is closed and fully written before it is read.
Show solution
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class WriteThenRead {
public static void main(String[] args) throws IOException {
File file = File.createTempFile("notes", ".txt");
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
writer.write("first");
writer.newLine();
writer.write("second");
writer.newLine();
}
int count = 0;
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line); // first, second
count++;
}
}
System.out.println(count); // 2
file.delete();
}
}
Quick quiz
1. Does new File("report.txt") create a file on disk?
- A. No; it only creates an object that represents the path
- B. Yes
- C. Only if the folder exists
- D. Only on Windows
Show answer
A. A File object is a path. The file is created by createNewFile() or by opening a writer on it.
2. What does new FileWriter("log.txt", true) do if the file already has content?
- A. Replaces the content
- B. Adds new text at the end
- C. Throws an exception
- D. Creates a second file
Show answer
B. The second argument turns on append mode. Without it the existing content is overwritten.
3. What happens if a BufferedWriter is neither flushed nor closed?
- A. Nothing; the data is already written
- B. The file is deleted
- C. Text still in the buffer may never reach the file
- D. It throws an exception
Show answer
C. The buffer is written out on flush() or close(), which is one reason to use try-with-resources.
Interview questions
What is the difference between File and FileReader?
Show answer
File represents a path and gives information about it, such as whether it exists, its size and whether it is a directory, and can create, rename or delete it. It never reads or writes content. FileReader is a character stream that opens a file and reads the text inside it.
How does try-with-resources work?
Show answer
Any object that implements AutoCloseable can be declared in the parentheses after try. When the block ends, normally or through an exception, close() is called on each resource in reverse order of declaration. If both the block and close() throw, the exception from the block is the one reported and the other is attached to it as a suppressed exception.
Key Points to Remember
- File represents a path and its metadata (exists, mkdir, delete); it does not read or write content.
- FileReader/FileWriter are character streams for text; they are inefficient without buffering.
- BufferedReader adds an internal buffer and the readLine() method, the standard way to read text line by line.
- try-with-resources automatically closes streams, even when an exception occurs.
Practice in the playground
Write and run your own code for this topic, or start from the exercise or an example. Runs plain Java 17. Frameworks such as Spring, and databases, are not available here. Your code for each topic is kept in this browser.
Run the examples
Change an input, predict the result, then compare it with the output. Explain why the result changes.
Written by
WebNest Studio Engineering Team
Practical lessons from developers working with Java, Python, React, databases and production systems.
Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering