Write code to perform file-processing operations

20.2 File Processing and Exception Handling

Learning Objective

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.


1. Syllabus Mapping – Quick Audit

Syllabus BlockCoverage in These NotesComments / 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.

2. File‑System Basics (Syllabus 20.2.1)

  • Absolute path – starts from the root of the file system (e.g. C:\data\file.txt or /home/user/file.txt).
  • Relative path – resolved against the program’s working directory (e.g. data/file.txt).
  • File permissions – read, write and execute rights that determine whether a program can open a file. Insufficient rights cause FileNotFoundException or AccessDeniedException.
  • Checking existence and type – use 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
        …
            
  • Creating / deleting
    f.createNewFile();   // creates an empty file
    f.mkdir();           // creates a directory
    f.delete();          // deletes file or empty directory
            
  • Copying / moving (NIO)
    Path src = Paths.get("students.csv");
    Path dst = Paths.get("backup/students_backup.csv");
    Files.copy(src, dst, StandardCopyOption.REPLACE_EXISTING);
            

3. Stream Classes Overview (All allowed in the 9618 exam)

CategoryClassTypical Use‑case (exam wording)
Character (text) streamsFileReaderLow‑level reading of characters from a file.
BufferedReaderEfficient line‑by‑line reading; provides readLine().
FileWriterLow‑level writing of characters to a file.
PrintWriterConvenient formatted output; optional auto‑flush.
Convenient text helpersScannerTokenised reading of text (e.g. nextInt(), nextLine()).
FormatterFormatted output similar to printf (used via PrintWriter).
Byte (binary) streamsFileInputStreamRead raw bytes from a file.
FileOutputStreamWrite raw bytes to a file.
DataInputStreamRead Java primitive types (int, double, …) from a binary stream.
DataOutputStreamWrite Java primitive types to a binary stream.
Object serialisationObjectInputStreamRead whole objects that implement Serializable.
ObjectOutputStreamWrite whole objects to a file.
Random‑accessRandomAccessFileRead/write at arbitrary positions; supports both text and binary data.

4. Text File Processing (Syllabus 20.2.2)

4.1 Reading with 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());
}

4.2 Tokenised reading with Scanner

Often 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");
}

4.3 Writing with 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());
}

4.4 Random‑Access Files (required for 20.2.2)

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);
}

5. Binary File Processing (Syllabus 20.2.2)

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());
}

6. Exception‑Handling Fundamentals (Syllabus 20.2.3)

  • Exception – an event that disrupts the normal flow of execution.
  • Checked exceptions (e.g. IOException, ClassNotFoundException) must be either caught or declared in a method’s throws clause.
  • Unchecked exceptions (sub‑classes of RuntimeException) need not be declared; examples: NullPointerException, ArrayIndexOutOfBoundsException.
  • Propagation – if a method does not catch an exception, it is passed up the call stack until a matching catch block is found or the JVM terminates the program.

6.1 The 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
}

6.2 Try‑with‑Resources (multiple resources)

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

6.3 Multi‑catch (single block for several exception types)

try {
    // …
} catch (InvalidRecordException | NumberFormatException e) {
    System.err.println("Skipping line: " + e.getMessage());
}

7. Custom Checked Exceptions (Syllabus 20.2.4)

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.


8. Integrated Example – CSV Processor with Backup & Logging

This example satisfies several exam requirements:

  • File‑system checks with File and Path.
  • Backup of the original file using Files.copy.
  • Reading with BufferedReader (line‑by‑line) and tokenising with String.split.
  • Writing valid records with PrintWriter and error details to a separate log file.
  • Use of a custom checked exception (InvalidRecordException).
  • All streams managed by a single try‑with‑resources statement.
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());
        }
    }
}

9. Summary Checklist (Exam‑style)

  • Know the difference between character and byte streams and be able to name the main classes for each.
  • Be able to choose the appropriate stream for:
    • Line‑by‑line text input – BufferedReader or Scanner.
    • Formatted text output – PrintWriter.
    • Primitive binary data – DataInput/OutputStream.
    • Random access – RandomAccessFile.
    • Object serialisation – ObjectInput/OutputStream.
  • Use absolute and relative paths correctly; check file existence with File or Path.
  • Always close streams – prefer try‑with‑resources; otherwise use a finally block.
  • Distinguish checked (IOException, ClassNotFoundException) from unchecked (NullPointerException) exceptions and handle them as required by the question.
  • When a method cannot recover from an exception, propagate it with a throws clause.
  • Write and use a custom checked exception for domain‑specific error conditions.
  • For binary files, remember to store the length (or a marker) when writing collections of primitives.
  • When using RandomAccessFile, calculate byte offsets correctly (e.g., int = 4 bytes, double = 8 bytes).

10. Practice Questions (All aligned with 20.2.1‑20.2.4)

QuestionKey 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.

11. Revision Diagram (optional)

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

92 views
0 improvement suggestions

Log in to suggest improvements to this note.