Lesson 147 min read

File I/O

Read from and write to files like a pro

Why File I/O?

So far, all your data disappears when the program ends — like writing on a whiteboard and erasing it. File I/O (Input/Output) lets you save data to files and read it back later. It's like writing in a notebook instead of on a whiteboard.

Java gives you several tools for working with files:

  • File — represents a file or directory path. Doesn't actually read or write, just points to a location.
  • Scanner — reads text from files (you already know it from reading user input!).
  • FileWriter / PrintWriter — writes text to files.
  • BufferedReader — reads files efficiently, line by line, using an internal buffer.

The key rule: always close your files when done. Or better yet, use try-with-resources so Java closes them for you.

Writing to a File

import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
// Method 1: PrintWriter — easy and familiar
try (PrintWriter writer = new PrintWriter(new FileWriter("scores.txt"))) {
writer.println("=== High Scores ===");
writer.println("Alice: 950");
writer.println("Bob: 870");
writer.println("Charlie: 920");
writer.printf("Average: %.1f%n", (950 + 870 + 920) / 3.0);
System.out.println("File written successfully!");
} catch (IOException e) {
System.out.println("Error writing file: " + e.getMessage());
}
// Method 2: Appending to an existing file (true = append mode)
try (PrintWriter appender = new PrintWriter(new FileWriter("scores.txt", true))) {
appender.println("Diana: 990"); // added to the end
System.out.println("Appended successfully!");
} catch (IOException e) {
System.out.println("Error appending: " + e.getMessage());
}
}
}
Output
File written successfully!
Appended successfully!

Reading Files

Reading a file is like opening a book — you can read it line by line, word by word, or all at once. The most common approaches:

  • Scanner — simple and familiar. Good for small files and parsing different data types.
  • BufferedReader — more efficient for large files. Reads chunks of data at once into a buffer (like loading several pages into memory instead of reading one character at a time).

Both should be used with try-with-resources to ensure the file gets closed properly, even if an error occurs.

Reading with Scanner

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// First, let's check if the file exists
File file = new File("scores.txt");
System.out.println("File exists: " + file.exists());
System.out.println("File name: " + file.getName());
System.out.println("Absolute path: " + file.getAbsolutePath());
System.out.println("---");
// Read the file line by line with Scanner
try (Scanner reader = new Scanner(file)) {
int lineNumber = 1;
while (reader.hasNextLine()) {
String line = reader.nextLine();
System.out.println(lineNumber + ": " + line);
lineNumber++;
}
} catch (FileNotFoundException e) {
System.out.println("File not found: " + e.getMessage());
}
}
}
Output
File exists: true
File name: scores.txt
Absolute path: /path/to/scores.txt
---
1: === High Scores ===
2: Alice: 950
3: Bob: 870
4: Charlie: 920
5: Average: 913.3
6: Diana: 990

BufferedReader — Efficient Reading

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.PrintWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
// First, create a sample CSV file
try (PrintWriter w = new PrintWriter(new FileWriter("students.csv"))) {
w.println("Name,Grade,Score");
w.println("Alice,A,95");
w.println("Bob,B,83");
w.println("Charlie,A,91");
w.println("Diana,C,74");
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
return;
}
// Read and parse the CSV with BufferedReader
ArrayList<String> honorRoll = new ArrayList<>();
try (BufferedReader br = new BufferedReader(new FileReader("students.csv"))) {
String header = br.readLine(); // skip header row
System.out.println("Header: " + header);
System.out.println("---");
String line;
while ((line = br.readLine()) != null) {
String[] parts = line.split(",");
String name = parts[0];
String grade = parts[1];
int score = Integer.parseInt(parts[2]);
System.out.printf("%s got a %s (%d)%n", name, grade, score);
if (score >= 90) {
honorRoll.add(name);
}
}
System.out.println("\nHonor Roll: " + honorRoll);
} catch (IOException e) {
System.out.println("Error reading: " + e.getMessage());
}
}
}
Output
Header: Name,Grade,Score
---
Alice got a A (95)
Bob got a B (83)
Charlie got a A (91)
Diana got a C (74)

Honor Roll: [Alice, Charlie]
Note: Always use try-with-resources for file operations. If your program crashes mid-read or mid-write without closing the file, the data might be lost or the file could stay locked. Try-with-resources is your safety net — it always closes the file, even when things go wrong.

Quick check

What does the File class actually do?
Exception HandlingLambdas & Streams