File class to inspect files and directoriesPrintWriterFileWriterScannerFileNotFoundException with try-catchEvery program you've written so far has one thing in common: when it stops running, all its data disappears. Variables live in RAM — and RAM is wiped clean the moment your program ends.
That's fine for small calculations, but most real programs need to persist data. A gradebook has to remember grades across sessions. A contact list needs to survive a reboot. A log file has to accumulate entries over time. That's what File I/O is for.
| Type | What's stored | Examples | Human-readable? |
|---|---|---|---|
| Text files | Characters (Unicode/ASCII) | .txt, .csv, .java, .html | Yes — open in Notepad |
| Binary files | Raw bytes | .jpg, .class, .exe, .zip | No — garbled in a text editor |
This module focuses on text files. They're the easiest to work with in Java, and they're everywhere — config files, logs, data exports, and more.
Before you read or write a file, Java gives you a way to represent it: the File class from java.io. A File object doesn't open the file — it's just a reference to a path on disk. Think of it as a pointer to a location.
import java.io.File;
public class FileDemo {
public static void main(String[] args) {
File f = new File("grades.txt"); // just a path reference
System.out.println("Name: " + f.getName());
System.out.println("Path: " + f.getPath());
System.out.println("Exists: " + f.exists());
System.out.println("IsFile: " + f.isFile());
System.out.println("Size: " + f.length() + " bytes");
}
}
| Method | Returns | What it tells you |
|---|---|---|
exists() | boolean | Does this path exist on disk? |
getName() | String | Just the filename, no directory path |
getPath() | String | The path as you wrote it |
getAbsolutePath() | String | Complete absolute path |
length() | long | Size in bytes |
isFile() | boolean | Is this a file (not a directory)? |
isDirectory() | boolean | Is this a directory? |
canRead() | boolean | Does your program have read permission? |
canWrite() | boolean | Does your program have write permission? |
new File("grades.txt") does not create the file on disk. It creates a Java object representing a path. The actual file gets created when you open a PrintWriter or FileWriter on it. Always check f.exists() before reading.
PrintWriter is the easiest way to write text to a file. You already know System.out.print() and System.out.println() — PrintWriter works exactly the same way, just aimed at a file instead of the console.
import java.io.PrintWriter;
import java.io.FileNotFoundException;
public class WriteDemo {
public static void main(String[] args) throws FileNotFoundException {
PrintWriter pw = new PrintWriter("output.txt");
pw.println("Alice: 92");
pw.println("Bob: 87");
pw.printf("Average: %.1f%n", 89.5);
pw.close(); // IMPORTANT: flushes buffer and closes the file
System.out.println("File written.");
}
}
After running this, output.txt will contain:
Alice: 92
Bob: 87
Average: 89.5
| Method | Does what |
|---|---|
print(value) | Writes value, no newline |
println(value) | Writes value + newline |
printf(format, args) | Formatted output — same syntax as System.out.printf |
close() | Flushes buffer and closes file |
flush() | Flushes buffer without closing |
pw.close(), some or all of the data may never make it to disk. Java buffers writes in memory and only flushes them on close. A file that looks empty usually means you forgot to close it.
output.txt already exists, new PrintWriter("output.txt") will erase it and start fresh. To add to an existing file, use FileWriter with the append flag (Section 4).
Sometimes you don't want to overwrite — you want to add to the end of an existing file. Log files are the classic example: every time the program runs, you append a new entry without losing the old ones.
The trick is FileWriter with a second argument of true:
import java.io.PrintWriter;
import java.io.FileWriter;
import java.io.IOException;
public class AppendDemo {
public static void main(String[] args) throws IOException {
// true = open in append mode (don't overwrite)
FileWriter fw = new FileWriter("log.txt", true);
PrintWriter pw = new PrintWriter(fw);
pw.println("Session started: " + new java.util.Date());
pw.println("User logged in.");
pw.close();
System.out.println("Entry appended.");
}
}
new PrintWriter("file.txt") is like ripping out all the pages of a notebook and starting fresh. new FileWriter("file.txt", true) is like opening to the last page and writing a new line.
FileWriter throws IOException (a broader exception), not just FileNotFoundException. Your method needs throws IOException or a try-catch for IOException.
You've used Scanner to read keyboard input. The exact same class reads files — you just give it a File object instead of System.in.
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
public class ReadDemo {
public static void main(String[] args) throws FileNotFoundException {
Scanner sc = new Scanner(new File("grades.txt"));
while (sc.hasNextLine()) {
String line = sc.nextLine();
System.out.println(line);
}
sc.close();
}
}
If grades.txt contains:
Alice: 92
Bob: 87
Carol: 95
Output:
Alice: 92
Bob: 87
Carol: 95
| Method | Returns | Use when |
|---|---|---|
hasNextLine() | boolean | Checking if another full line exists |
nextLine() | String | Reading one complete line |
hasNext() | boolean | Checking if another token (word) exists |
next() | String | Reading one whitespace-delimited word |
hasNextInt() | boolean | Checking if next token is an integer |
nextInt() | int | Reading one integer |
hasNextDouble() | boolean | Checking if next token is a double |
nextDouble() | double | Reading one double |
close() | void | Done reading — always close |
hasNextLine() when reading structured records — one full line at a time. Use hasNext() when scanning for individual tokens (words, numbers) regardless of line breaks.
numbers.txt with five integers, one per line. Write a program that reads each number using Scanner and prints the number doubled. Close the scanner when done.
File operations can fail in ways normal code can't. The file might not exist, permissions might block access, or the disk might be full. Java forces you to deal with this through checked exceptions.
The most common one for file reading is FileNotFoundException.
Add throws FileNotFoundException to your method signature. This passes responsibility to the caller:
public static void main(String[] args) throws FileNotFoundException {
Scanner sc = new Scanner(new File("data.txt"));
// ... read the file ...
}
Simple, but the program crashes with a stack trace if the file isn't found. Fine for learning. Not great for production.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class SafeRead {
public static void main(String[] args) {
try {
Scanner sc = new Scanner(new File("data.txt"));
while (sc.hasNextLine()) {
System.out.println(sc.nextLine());
}
sc.close();
} catch (FileNotFoundException e) {
System.out.println("Error: File not found.");
System.out.println(e.getMessage());
}
}
}
If data.txt exists — output is file contents. If it doesn't:
Error: File not found.
data.txt (No such file or directory)
throws is like saying "not my problem — you deal with it." try-catch is like saying "I'll handle this right here." For files, try-catch is almost always the right choice in real programs because it lets you give the user a clear message.
} catch (FileNotFoundException e) {
// do nothing — BAD PRACTICE
}
At minimum, print the exception message so you know something went wrong.
Manually calling close() works, but there's a cleaner approach: try-with-resources. Declare your file object inside the try parentheses, and Java automatically closes it when the block ends — even if an exception occurs.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class TryWithResources {
public static void main(String[] args) {
try (Scanner sc = new Scanner(new File("data.txt"))) {
while (sc.hasNextLine()) {
System.out.println(sc.nextLine());
}
} catch (FileNotFoundException e) {
System.out.println("File not found: " + e.getMessage());
}
// sc is automatically closed here — no close() needed
}
}
You can open multiple resources in the same try, separated by semicolons:
try (Scanner sc = new Scanner(new File("input.txt"));
PrintWriter pw = new PrintWriter("output.txt")) {
while (sc.hasNextLine()) {
pw.println(sc.nextLine().toUpperCase());
}
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
// Both sc and pw are automatically closed
close(), if an exception fires before you reach the close call, the file stays open. Try-with-resources closes the file no matter what happens — exception or not. Make it your default for any file work.
Reading a file line by line is just the start. Here are three patterns you'll use constantly.
try (Scanner sc = new Scanner(new File("data.txt"))) {
int count = 0;
while (sc.hasNextLine()) {
sc.nextLine(); // consume the line
count++;
}
System.out.println("Total lines: " + count);
} catch (FileNotFoundException e) {
System.out.println("File not found.");
}
File scores.txt — one integer per line:
try (Scanner sc = new Scanner(new File("scores.txt"))) {
int sum = 0;
int count = 0;
while (sc.hasNextInt()) {
sum += sc.nextInt();
count++;
}
if (count > 0) {
System.out.printf("Sum: %d%n", sum);
System.out.printf("Average: %.2f%n", (double) sum / count);
}
} catch (FileNotFoundException e) {
System.out.println("File not found.");
}
If scores.txt contains 85, 92, 78, 96, 88 (one per line):
Sum: 439
Average: 87.80
CSV (Comma-Separated Values) is one of the most common data formats. Each line holds fields separated by commas:
// students.csv:
// Alice,92,88,95
// Bob,78,82,80
// Carol,95,91,97
try (Scanner sc = new Scanner(new File("students.csv"))) {
while (sc.hasNextLine()) {
String line = sc.nextLine();
String[] parts = line.split(",");
String name = parts[0];
int s1 = Integer.parseInt(parts[1]);
int s2 = Integer.parseInt(parts[2]);
int s3 = Integer.parseInt(parts[3]);
double avg = (s1 + s2 + s3) / 3.0;
System.out.printf("%-10s avg: %.1f%n", name, avg);
}
} catch (FileNotFoundException e) {
System.out.println("File not found.");
}
Output:
Alice avg: 91.7
Bob avg: 80.0
Carol avg: 94.3
Integer.parseInt() will throw NumberFormatException. Validate your data or wrap the parse in its own try-catch.
words.txt with one word per line. Write a program that reads every word, prints it in uppercase, and then prints the total word count at the end.
Let's put it all together. This program reads student records from an input file, calculates each student's average, and writes a formatted report to an output file.
Alice,85,92,88
Bob,70,75,68
Carol,95,98,100
David,60,72,65
import java.io.File; import java.io.FileNotFoundException; import java.io.PrintWriter; import java.util.Scanner; public class GradeProcessor { public static void main(String[] args) { String inputFile = "students.csv"; String outputFile = "report.txt"; try (Scanner sc = new Scanner(new File(inputFile)); PrintWriter pw = new PrintWriter(outputFile)) { pw.println("=== Grade Report ==="); pw.println(); while (sc.hasNextLine()) { String line = sc.nextLine().trim(); if (line.isEmpty()) continue; // skip blank lines String[] parts = line.split(","); String name = parts[0]; int s1 = Integer.parseInt(parts[1]); int s2 = Integer.parseInt(parts[2]); int s3 = Integer.parseInt(parts[3]); double avg = (s1 + s2 + s3) / 3.0; String grade = getLetterGrade(avg); pw.printf("%-10s Scores: %d, %d, %d | Avg: %.1f | Grade: %s%n", name, s1, s2, s3, avg, grade); } pw.println(); pw.println("Report generated by GradeProcessor.java"); } catch (FileNotFoundException e) { System.out.println("Input file not found: " + e.getMessage()); } catch (Exception e) { System.out.println("Error processing file: " + e.getMessage()); } System.out.println("Done. See " + outputFile); } public static String getLetterGrade(double avg) { if (avg >= 90) return "A"; if (avg >= 80) return "B"; if (avg >= 70) return "C"; if (avg >= 60) return "D"; return "F"; } }Output File: report.txt
=== Grade Report === Alice Scores: 85, 92, 88 | Avg: 88.3 | Grade: B Bob Scores: 70, 75, 68 | Avg: 71.0 | Grade: C Carol Scores: 95, 98, 100 | Avg: 97.7 | Grade: A David Scores: 60, 72, 65 | Avg: 65.7 | Grade: D Report generated by GradeProcessor.javaNotice how this program combines everything from this module: reading CSV data with
Scanner, parsing withsplit()andparseInt(), calculating results, writing formatted output withPrintWriter, and using try-with-resources for both files at once.Try It — Extend the ProgramModify the grade processor to also calculate and write the class average at the bottom of the report. You'll need to track the running total and student count across the loop.Key Terms
Term Definition FileA Java class representing a path to a file or directory — does not open or create the file itself. PrintWriterA class for writing formatted text to a file. Supports print(),println(),printf().FileWriterLower-level writer; used with the append flag ( true) to add data without overwriting.Scanner(file)The same Scanner you know — pointed at a Fileobject instead ofSystem.in.FileNotFoundException Thrown when you try to open a file that doesn't exist or can't be accessed. IOException Broader I/O exception; parent of FileNotFoundException. Used with FileWriter.Try-with-resources A try block that automatically closes declared resources when the block exits. Append mode Opening a file for writing without erasing its existing content. CSV Comma-Separated Values — a plain text format where fields on each line are separated by commas. split(",")String method that splits a string on a delimiter and returns an array of the pieces. Module Summary
- File I/O lets programs persist data beyond a single run — RAM is temporary, files are not.
- The File class represents a path; it doesn't open or create anything on its own.
- PrintWriter writes text to a file using the same methods as
System.out; always callclose().- FileWriter with true opens a file in append mode — existing content is preserved.
- Scanner(new File(...)) reads a text file the same way you read keyboard input.
- FileNotFoundException is a checked exception — handle it with try-catch or declare
throws.- Try-with-resources automatically closes files — use it by default.
- Common processing patterns: count lines, sum/average numbers, parse CSV with
split().Module 11 Quiz — File I/O
Name: _________________________ Date: _____________ Score: ______ / 10
Circle the best answer for each question.
1.What does
new File("grades.txt")do in Java?2.Which statement about RAM vs. files is correct?
3.What is the output of the following code if
output.txtalready contains the line "Hello"?PrintWriter pw = new PrintWriter("output.txt"); pw.println("World"); pw.close();4.Which constructor opens a file so that new data is added to the end without erasing existing content?
5.A file named
data.txtcontains:10 20 30What does this code print?
Scanner sc = new Scanner(new File("data.txt")); int sum = 0; while (sc.hasNextInt()) { sum += sc.nextInt(); } sc.close(); System.out.println(sum);6.Which exception must be handled when using
new Scanner(new File("f.txt"))?7.What is the main advantage of try-with-resources over manually calling
close()?8.Given the line
String line = "Alice,92,88,95";, what doesline.split(",")[1]return?9.Which
Filemethod returnstrueif the path exists and is a regular file (not a directory)?10.You want to read a file and write a transformed version to another file. Which approach correctly uses try-with-resources with both files open at the same time?
✅ Answer Key
| Question | Answer | Explanation |
|---|---|---|
| 1 | A | The File class represents a file or directory path. |
| 2 | C | A Scanner can read from a file by passing a File object to its constructor. |
| 3 | B | PrintWriter writes formatted text to a file. |
| 4 | D | A FileNotFoundException occurs when the specified file does not exist. |
| 5 | A | hasNextLine() returns true if there is another line to read. |
| 6 | D | The throws clause declares that a method may throw a checked exception. |
| 7 | A | try-with-resources automatically closes files when the block finishes. |
| 8 | B | Appending to a file uses new FileWriter("file.txt", true) with the append flag. |
| 9 | D | A BufferedReader reads text efficiently by buffering chunks of data. |
| 10 | C | The exists() method checks whether a file or directory exists before accessing it. |