Write Java programs that read from and write to text, binary and random‑access files, and handle any resulting exceptions safely and idiomatically, using the terminology and concepts required by the Cambridge 9618 (2026) syllabus.
| Syllabus Block | Coverage in These Notes | Comments / Additions |
|---|---|---|
| 20.2.1 – File‑system basics | Absolute/relative paths, permissions, existence checks, creating/deleting files and directories. | Added explicit terminology and examples; included java.nio.file utilities for copying. |
| 20.2.2 – Text, binary and random‑access files | All stream classes, Scanner, BufferedReader, PrintWriter, DataInput/OutputStream, RandomAccessFile. |
Added Scanner example for line‑by‑line tokenised input; clarified when each class is required. |
| 20.2.3 – Exception handling | Checked vs unchecked, try‑catch‑finally, try‑with‑resources, multi‑catch, propagation. |
All concepts retained; emphasised exam‑style phrasing. |
| 20.2.4 – Custom exceptions | Definition, throwing, catching, and declaring custom checked exceptions. | Example retained; linked to a realistic CSV‑processing scenario. |
C:\data\file.txt or /home/user/file.txt).data/file.txt).FileNotFoundException or AccessDeniedException.java.io.File (or java.nio.file.Path)
File f = new File("data.txt");
if (!f.exists()) // file does not exist
…
if (f.isFile()) // regular file
…
if (f.isDirectory()) // directory
…
f.createNewFile(); // creates an empty file
f.mkdir(); // creates a directory
f.delete(); // deletes file or empty directory
Path src = Paths.get("students.csv");
Path dst = Paths.get("backup/students_backup.csv");
Files.copy(src, dst, StandardCopyOption.REPLACE_EXISTING);
| Category | Class | Typical Use‑case (exam wording) |
|---|---|---|
| Character (text) streams | FileReader | Low‑level reading of characters from a file. |
BufferedReader | Efficient line‑by‑line reading; provides readLine(). | |
FileWriter | Low‑level writing of characters to a file. | |
PrintWriter | Convenient formatted output; optional auto‑flush. | |
| Convenient text helpers | Scanner | Tokenised reading of text (e.g. nextInt(), nextLine()). |
Formatter | Formatted output similar to printf (used via PrintWriter). | |
| Byte (binary) streams | FileInputStream | Read raw bytes from a file. |
FileOutputStream | Write raw bytes to a file. | |
DataInputStream | Read Java primitive types (int, double, …) from a binary stream. | |
DataOutputStream | Write Java primitive types to a binary stream. | |
| Object serialisation | ObjectInputStream | Read whole objects that implement Serializable. |
ObjectOutputStream | Write whole objects to a file. | |
| Random‑access | RandomAccessFile | Read/write at arbitrary positions; supports both text and binary data. |
BufferedReader
try (BufferedReader br = new BufferedReader(new FileReader("input.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
System.err.println("Read error: " + e.getMessage());
}
ScannerOften required when the file contains numbers or delimited fields.
try (Scanner sc = new Scanner(new File("scores.txt"))) {
while (sc.hasNextInt()) {
int score = sc.nextInt();
System.out.println("Score: " + score);
}
} catch (FileNotFoundException e) {
System.err.println("File not found");
}
PrintWriter
try (PrintWriter pw = new PrintWriter(new FileWriter("output.txt"))) {
pw.println("First line");
pw.println("Second line");
} catch (IOException e) {
System.err.println("Write error: " + e.getMessage());
}
RandomAccessFile implements both DataInput and DataOutput. Use seek(long pos) to move the file pointer and getFilePointer() to query its location.
try (RandomAccessFile raf = new RandomAccessFile("records.bin", "rw")) {
// Write three integers (4 bytes each)
raf.writeInt(10);
raf.writeInt(20);
raf.writeInt(30);
// Read the second integer (index 1)
raf.seek(4); // skip first int (4 bytes)
int second = raf.readInt(); // 20
System.out.println("Second = " + second);
// Overwrite it with 99
raf.seek(4);
raf.writeInt(99);
}
int[] numbers = {5, 12, 7, 19};
/* Write the array */
try (DataOutputStream dos = new DataOutputStream(
new FileOutputStream("ints.bin"))) {
dos.writeInt(numbers.length); // store length first
for (int n : numbers) {
dos.writeInt(n);
}
} catch (IOException e) {
System.err.println("Write error: " + e.getMessage());
}
/* Read the array back */
try (DataInputStream dis = new DataInputStream(
new FileInputStream("ints.bin"))) {
int len = dis.readInt();
int[] readBack = new int[len];
for (int i = 0; i < len; i++) {
readBack[i] = dis.readInt();
}
System.out.println(java.util.Arrays.toString(readBack));
} catch (IOException e) {
System.err.println("Read error: " + e.getMessage());
}
IOException, ClassNotFoundException) must be either caught or declared in a method’s throws clause.RuntimeException) need not be declared; examples: NullPointerException, ArrayIndexOutOfBoundsException.catch block is found or the JVM terminates the program.try‑catch‑finally Construct
try {
// code that may throw an exception
} catch (FileNotFoundException e) {
// specific handling
} catch (IOException e) {
// handling for other I/O problems
} finally {
// always executed – useful for explicit clean‑up
}
Any object that implements java.lang.AutoCloseable (all stream classes) can be declared in the resource specification. Resources are closed automatically, in reverse order of creation.
try (BufferedReader br = new BufferedReader(new FileReader("in.txt"));
PrintWriter pw = new PrintWriter(new FileWriter("out.txt"))) {
// use br and pw
} catch (IOException e) {
System.err.println(e);
} // br and pw are closed here
try {
// …
} catch (InvalidRecordException | NumberFormatException e) {
System.err.println("Skipping line: " + e.getMessage());
}
public class InvalidRecordException extends Exception {
public InvalidRecordException(String message) {
super(message);
}
}
Use custom checked exceptions to signal domain‑specific problems (e.g. malformed CSV rows). They must be declared or caught just like any other checked exception.
This example satisfies several exam requirements:
File and Path.Files.copy.BufferedReader (line‑by‑line) and tokenising with String.split.PrintWriter and error details to a separate log file.InvalidRecordException).
import java.io.*;
import java.nio.file.*;
public class CSVProcessor {
public static void main(String[] args) {
String inputPath = "students.csv";
String goodPath = "valid_students.txt";
String logPath = "error_log.txt";
String backupDir = "backup";
/* 1. Verify input file exists */
File inputFile = new File(inputPath);
if (!inputFile.exists() || !inputFile.isFile()) {
System.err.println("Input file not found: " + inputPath);
return;
}
/* 2. Create a backup copy before processing */
try {
Files.createDirectories(Paths.get(backupDir));
Path source = inputFile.toPath();
Path target = Paths.get(backupDir, inputFile.getName());
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
System.err.println("Backup failed: " + e.getMessage());
// continue – backup is optional
}
/* 3. Process the CSV file */
try (BufferedReader br = new BufferedReader(new FileReader(inputFile));
PrintWriter goodPw = new PrintWriter(new FileWriter(goodPath));
PrintWriter logPw = new PrintWriter(new FileWriter(logPath))) {
String line;
int lineNum = 0;
while ((line = br.readLine()) != null) {
lineNum++;
try {
String[] fields = line.split(",");
if (fields.length != 3) {
throw new InvalidRecordException(
"Expected 3 fields, found " + fields.length);
}
String name = fields[0].trim();
int age = Integer.parseInt(fields[1].trim());
double gpa = Double.parseDouble(fields[2].trim());
if (age < 0 || gpa < 0.0) {
throw new InvalidRecordException("Negative age or GPA");
}
// Record is valid – write to the “good” file
goodPw.printf("%s,%d,%.2f%n", name, age, gpa);
} catch (InvalidRecordException | NumberFormatException e) {
// Write a detailed message to the log file
logPw.printf("Line %d skipped – %s%n", lineNum, e.getMessage());
}
}
} catch (IOException e) {
System.err.println("I/O problem: " + e.getMessage());
}
}
}
BufferedReader or Scanner.PrintWriter.DataInput/OutputStream.RandomAccessFile.ObjectInput/OutputStream.File or Path.try‑with‑resources; otherwise use a finally block.IOException, ClassNotFoundException) from unchecked (NullPointerException) exceptions and handle them as required by the question.throws clause.RandomAccessFile, calculate byte offsets correctly (e.g., int = 4 bytes, double = 8 bytes).| Question | Key Concepts Tested |
|---|---|
Write a method int countErrorLines(String fileName) that returns the number of lines containing the word “error”. Include appropriate exception handling. |
BufferedReader, readLine(), String.contains(), try‑with‑resources, returning -1 on I/O failure. |
| Explain the difference between a checked and an unchecked exception, giving one example of each. | Theory – compile‑time requirement, IOException vs ArrayIndexOutOfBoundsException. |
| Modify the CSV processor example so that it also creates a backup copy of the original input file before processing. | Use java.nio.file.Files.copy, directory creation, additional exception handling. |
Demonstrate how to use RandomAccessFile to store 100 integer scores, then update the score at position 57 without reading the whole file. |
Random‑access file, seek, byte offset calculation (57 × 4), writeInt. |
Write code that writes an array of Student objects to a file using ObjectOutputStream and then reads them back with ObjectInputStream. Include all necessary exception handling. |
Object serialisation, Serializable interface, try‑with‑resources, handling IOException and ClassNotFoundException. |
Using Scanner, read a text file that contains one integer per line and compute the average. Show how you would handle a line that does not contain a valid integer. |
Scanner tokenisation, hasNextInt(), nextInt(), NumberFormatException handling. |
Typical flow of file processing in an exam answer:
Open (try‑with‑resources) → Read / Write (loop) → Handle specific exceptions (catch) → • If recoverable → continue • If not → propagate or terminate Close (automatic) → Report result
Remember to mention the resource‑closing order (last opened, first closed) if the question asks for it.
Create an account or Login to take a Quiz
Log in to suggest improvements to this note.
Your generous donation helps us continue providing free Cambridge IGCSE & A-Level resources, past papers, syllabus notes, revision questions, and high-quality online tutoring to students across Kenya.