File Processing

IB Syllabus: B2.5 — File processing

Table of Contents

  1. Why Files?
  2. Reading a File
    1. Reading and Processing Values
  3. Writing to a File
  4. Appending to a File
  5. Reading with BufferedReader
  6. Writing with BufferedWriter
  7. Exception Handling in File Processing
  8. A Complete Example: Student Grade Logger
  9. Summary
  10. Quick Check
  11. Practice Exercises

Why Files?

Every program so far has used Scanner to read from the keyboard and System.out.println to write to the screen. When the program ends, all data disappears.

Files allow programs to persist data — to read information that was stored by a previous run, and to save results that will outlast the current session. A student record system, a game’s high score list, or a bank’s transaction log all need file processing.


Picture it: A file called scores.txt sits on the hard drive with 30 lines of student names and scores. How does your program reach that data? The answer is the same Scanner you already know — just pointed at a file instead of the keyboard.

Reading a File

Java’s Scanner class can read from a file just as easily as from the keyboard — the only difference is what you pass to its constructor.

import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;

public class ReadFile {
    public static void main(String[] args) {
        try {
            File file = new File("scores.txt");
            Scanner reader = new Scanner(file);

            while (reader.hasNextLine()) {
                String line = reader.nextLine();
                System.out.println(line);
            }

            reader.close();

        } catch (FileNotFoundException e) {
            System.out.println("Error: file not found.");
        }
    }
}

Assume scores.txt contains:

Alice 85
Bob 72
Charlie 91

Output:

Alice 85
Bob 72
Charlie 91

Reading and Processing Values

You can parse the data from each line rather than just printing it:

try {
    Scanner reader = new Scanner(new File("scores.txt"));

    int total = 0;
    int count = 0;

    while (reader.hasNextLine()) {
        String line = reader.nextLine();
        Scanner lineScanner = new Scanner(line);

        String name = lineScanner.next();       // read the name
        int score = lineScanner.nextInt();       // read the score

        System.out.println(name + " scored " + score);
        total += score;
        count++;
    }

    reader.close();
    System.out.println("Average: " + (double) total / count);

} catch (FileNotFoundException e) {
    System.out.println("File not found.");
}

reader.hasNextLine() returns true as long as there is another line to read. This is the standard loop condition for reading files of unknown length.


Think about it: If you open a text file and start typing, what happens to the existing content? What if you wanted to add to the end without replacing it? There are two different modes for exactly these two cases.

Writing to a File

FileWriter writes text to a file. By default, it overwrites any existing content.

import java.io.FileWriter;
import java.io.IOException;

public class WriteFile {
    public static void main(String[] args) {
        try {
            FileWriter writer = new FileWriter("output.txt");

            writer.write("Alice,85\n");
            writer.write("Bob,72\n");
            writer.write("Charlie,91\n");

            writer.close();
            System.out.println("File written successfully.");

        } catch (IOException e) {
            System.out.println("Error writing file: " + e.getMessage());
        }
    }
}

Always call writer.close(). Failing to close a file may result in data not being flushed to disk — some content could be lost.


Appending to a File

To add content to the end of an existing file without overwriting it, pass true as the second argument to FileWriter.

try {
    FileWriter writer = new FileWriter("log.txt", true);   // true = append mode

    writer.write("New entry added to log.\n");

    writer.close();

} catch (IOException e) {
    System.out.println("Error: " + e.getMessage());
}
Mode Constructor Behaviour
Overwrite new FileWriter("file.txt") Clears existing content, starts fresh
Append new FileWriter("file.txt", true) Adds to end of existing content

Reading with BufferedReader

BufferedReader is more efficient for reading large files because it reads data in chunks (a buffer) rather than one character at a time.

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class BufferedReadFile {
    public static void main(String[] args) {
        try {
            BufferedReader reader = new BufferedReader(new FileReader("scores.txt"));

            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }

            reader.close();

        } catch (IOException e) {
            System.out.println("Error reading file: " + e.getMessage());
        }
    }
}

The condition (line = reader.readLine()) != null does two things at once:

  1. Reads the next line and assigns it to line
  2. Checks if readLine() returned null (which signals end-of-file)
Class Used for Efficiency
Scanner(File) Small files, mixed types (int, String) Lower
BufferedReader Line-by-line text, larger files Higher

Writing with BufferedWriter

For writing, BufferedWriter wraps FileWriter to buffer output and add the newLine() convenience method.

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class BufferedWriteFile {
    public static void main(String[] args) {
        try {
            BufferedWriter writer = new BufferedWriter(new FileWriter("results.txt"));

            writer.write("Name,Score");
            writer.newLine();
            writer.write("Alice,85");
            writer.newLine();
            writer.write("Bob,72");
            writer.newLine();

            writer.close();

        } catch (IOException e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}

writer.newLine() inserts the correct line separator for the operating system (Windows uses \r\n, macOS/Linux use \n). This is better practice than hardcoding "\n".


Before reading: List every way a file operation could fail. The exception handling pattern below covers each one — match them up as you read.

Exception Handling in File Processing

File operations can fail in predictable ways:

  • The file does not exist (FileNotFoundException)
  • The directory has no write permission (IOException)
  • The file is already in use by another process

Always wrap file operations in try/catch/finally. The finally block ensures the file is closed even if an exception occurs.

import java.io.*;

public class SafeFileRead {
    public static void main(String[] args) {
        BufferedReader reader = null;

        try {
            reader = new BufferedReader(new FileReader("data.txt"));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }

        } catch (FileNotFoundException e) {
            System.out.println("File not found: " + e.getMessage());

        } catch (IOException e) {
            System.out.println("Read error: " + e.getMessage());

        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    System.out.println("Could not close file.");
                }
            }
        }
    }
}

The reader is declared outside the try block so it is accessible in finally. Inside the try, it is opened. The finally block closes it regardless of what happened. This pattern prevents resource leaks.


A Complete Example: Student Grade Logger

This program reads existing scores from a file, calculates the class average, and appends a new score entered by the user.

import java.util.Scanner;
import java.io.*;

public class GradeLogger {
    public static void main(String[] args) {
        String filename = "grades.txt";

        // Step 1: Read and display existing scores
        System.out.println("--- Current Scores ---");
        try {
            BufferedReader reader = new BufferedReader(new FileReader(filename));
            String line;
            int total = 0;
            int count = 0;

            while ((line = reader.readLine()) != null) {
                System.out.println(line);
                total += Integer.parseInt(line.trim());
                count++;
            }

            reader.close();

            if (count > 0) {
                System.out.println("Average: " + (double) total / count);
            }

        } catch (FileNotFoundException e) {
            System.out.println("(No existing file — starting fresh.)");
        } catch (IOException e) {
            System.out.println("Error reading file.");
        }

        // Step 2: Add a new score
        Scanner input = new Scanner(System.in);
        System.out.print("\nEnter new score to add: ");
        int newScore = input.nextInt();

        try {
            FileWriter writer = new FileWriter(filename, true);   // append
            writer.write(newScore + "\n");
            writer.close();
            System.out.println("Score saved.");

        } catch (IOException e) {
            System.out.println("Error saving score.");
        }
    }
}

Summary

Task Classes to use
Read a small file, mixed types Scanner(new File(...))
Read a large text file line-by-line BufferedReader(new FileReader(...))
Write to a file (overwrite) FileWriter("file.txt")
Append to a file FileWriter("file.txt", true)
Write efficiently with newlines BufferedWriter(new FileWriter(...))
Always Wrap in try/catch, close in finally

Quick Check

Q1. new FileWriter("log.txt") — what happens to any content already in log.txt?

Q2. Which constructor appends to a file rather than overwriting it?

Q3. What does reader.hasNextLine() return when there are no more lines?

Q4. Why is the finally block important when working with files?

Q5. Why is BufferedReader preferred over Scanner for reading large files?


Practice Exercises

  1. Write a program that reads integers from a file called numbers.txt (one per line) and prints the sum and count.
  2. Write a program that asks the user for five names and writes them to a file called names.txt, one per line.
  3. Modify exercise 2 to append (not overwrite) each time the program runs. Run it twice and verify the file grows.
  4. Write a program that copies all lines from input.txt to output.txt, converting each line to uppercase.
  5. Challenge: Write a program that reads a CSV file where each line is name,score (e.g. Alice,85). Parse each line, calculate the class average, and write a summary to a new file summary.txt that lists all names with their scores and the overall average at the bottom.

Back to top

© EduCS.me — A resource hub for IB Computer Science

This site uses Just the Docs, a documentation theme for Jekyll.