Reading and writing files

In Lesson 13.1 you opened streams by hand. For everyday jobs (save a list, append an order, read a CSV, move a report) Java gives you one-line helpers in java.nio.file.Files, driven by Path objects. You'll learn to create, write, append, read, copy, move and delete files and folders, understand where relative paths point, and handle the errors files bring.

Module 13 · File Handling and I/O⏱ 22 minIntermediate9 practice problems
1 The story

“Where did today's orders go?”

Riya's canteen app now writes each order to orders.csv. At night the owner opens the file and finds only the last order. Riya also can't find the file on her laptop: it isn't in the folder where her code is.

canteen-app/ data/ orders.csv src/Main.java working directory overwrite 09:10,dosa,80 12:45,thali,120 16:30,chai,15 append 09:10,dosa,80 12:45,thali,120 16:30,chai,15 myphatshala.in
Riya

Sir, I write every order, but only the last one stays!

Arjun Sir

Writing a file normally replaces it. To add at the end you must ask for append. And the file is where your program ran from, the working directory, not where your code sits.

Riya

Is there an easy way, without all those stream classes?

Arjun Sir

Yes: Path to name the file, and Files to do the work in one line each. Let's see what each line does on disk.

2 Definition

What are Path and Files?

Formal definition (write this in exams)

java.nio.file.Path is an object that represents the location of a file or directory in the file system as a sequence of names; it may be absolute (from the root) or relative (resolved against the current working directory), and creating a Path does not access the disk. java.nio.file.Files is a utility class of static methods that operate on paths: creating, reading, writing, copying, moving and deleting files and directories and querying their attributes. Its methods open and close the required streams internally, use UTF-8 for text by default, and report failures by throwing IOException subclasses such as NoSuchFileException and FileAlreadyExistsException. The older java.io.File class serves a similar purpose.

In simple words

A Path is an address written on an envelope. Files is the postman who actually goes there to drop off, pick up, copy or remove things.

Words you'll meet in this lesson

Absolute pathFull location from the root: /home/riya/app/data/x.csv or E:\app\x.csv.
Relative pathLocation from the working directory: data/x.csv.
Working directoryFolder the program was started from: System.getProperty("user.dir").
AppendAdd to the end of a file instead of replacing it.
CSVComma-separated values: a plain text table, one row per line.
resolve()Join paths: dir.resolve("a.txt") → dir/a.txt.

Old and new file APIs

java.io.File (old)Path + Files (Java 7+)
Name a filenew File("a.txt")Path.of("a.txt")
Read whole textopen a reader and loopFiles.readString(p)
Errorsoften just false (e.g. delete())specific exceptions with reasons
Copy / movenot built inFiles.copy, Files.move
Default charsetplatform default (UTF-8 since Java 18)UTF-8
Convertfile.toPath()path.toFile()

Exam tip: “Files.writeString/write create the file if needed and truncate it by default; pass StandardOpenOption.APPEND to add. Reading a missing file throws NoSuchFileException (NIO) or FileNotFoundException (java.io), both subclasses of IOException.”

3 Types and ways to use it

Your file toolkit

Path p = Path.of("data", "orders.csv");          // just a name
Files.exists(p)    Files.size(p)    Files.isDirectory(p)
Files.writeString(p, text)                        // create or replace
Files.writeString(p, text, StandardOpenOption.APPEND)
Files.write(p, listOfLines)
String all = Files.readString(p);
List<String> lines = Files.readAllLines(p);
Files.createDirectories(p.getParent());
Files.copy(a, b)   Files.move(a, b)   Files.delete(p)   Files.deleteIfExists(p)

Small text files

readString, writeString, readAllLines, write(lines): one line each.

Files

Folders

createDirectories, list, isDirectory, walk for whole trees.

directories

Copy, move, delete

copy, move, delete, deleteIfExists, with explicit overwrite options.

management

Scanner & PrintWriter

Read tokens and numbers from a file; write with println/printf.

familiar style

The older java.io.File

import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
        File f = new File("legacy.txt");
        try (FileWriter w = new FileWriter(f)) {
            w.write("written with java.io.File");
        }
        System.out.println(f.getName() + " exists=" + f.exists() + " size=" + f.length());
        System.out.println("deleted: " + f.delete() + ", deleted again: " + f.delete());
    }
}
legacy.txt exists=true size=25 deleted: true, deleted again: false

Don't trust relative paths in servers and IDEs. “data/orders.csv” goes wherever the program was started: the project root in an IDE, some other folder on a server. For important files, build the path from a configured base folder: Path.of(config.dataDir(), "orders.csv").

4 Step by step

What happens when you call Files.writeString

  1. Resolve the path

    Files.writeString(Path.of("data", "orders.csv"), "101,dosa,80\n");
    The relative path is joined to the working directory, e.g. /home/riya/app/data/orders.csv.
  2. Open with options

    With no options it opens with CREATE + TRUNCATE_EXISTING + WRITE: create the file if missing, empty it if present. If the folder data doesn't exist, you get NoSuchFileException, so create folders first.
  3. Encode and write

    The text is encoded as UTF-8 and written through a byte stream, as in Lesson 13.1.
  4. Close

    The method closes the stream before returning, so the data is handed to the OS and the file handle is released. There is nothing for you to forget.
  5. Or append

    Files.writeString(p, "102,idli,40\n", StandardOpenOption.APPEND);
    APPEND moves the write position to the end; existing bytes are kept. (Add CREATE too if the file might not exist yet.)
5 See it happen

From Path to file and back: both views

Left: the folder and file as you'd see them in a file manager. Right: the Path and List objects on the heap, and the file as the operating system holds it.

Paths and files, both views 6 steps
What you see Path p = Path.of("data", "orders.csv"); Files.createDirectories(p.getParent()); Files.writeString(p, "101,dosa,80\n"); Files.writeString(p, "102,idli,40\n", APPEND); List<String> lines = Files.readAllLines(p); Files.delete(p); app/ (working directory) data/ orders.csv (no data folder yet) (deleted) orders.csv contents 101,dosa,80 102,idli,40 12 bytes 24 bytes lines (a List in memory) [101,dosa,80, 102,idli,40] a Path names a file; it doesn't create one Just a name, nothing on disk. The folder is created. File created and written. A second line appended. Whole file read into a List. File deleted. myphatshala.in
Behind the screen JVM HEAP #1 Path "data/orders.csv" #2 ArrayList (2) #3 "101,dosa,80" #4 "102,idli,40" OPERATING SYSTEM working dir: /home/riya/app data/ — data/ folder orders.csv — orders.csv 12 B orders.csv 24 B orders.csv — inside writeString: open → encode → write → close inside readAllLines: open → read → decode → split lines → close A Path object, no file. OS creates the folder. Stream opened and closed for you. Appended: 24 bytes. New List + Strings on the heap. OS removes the file. myphatshala.in
6 Real-world use

Files in real systems

Even apps backed by databases read and write plenty of files: imports, exports, configs, logs and archives.

Watch it with an example: a canteen's daily sales file

Every order is appended to one CSV file per day. At closing time the owner's report reads the file and adds up the sales.

Append all day, read at night 5 steps
Animated example sales-2026-10-16.csv 09:10,dosa,80 12:45,thali,120 16:30,chai,15 APPEND readAllLines() split(",")[2] 80+120+15 Today's sales: 3 orders, Rs 215 Morning: first order appended. Lunch: another line. Evening: another line. Night: read every line. Report the total. myphatshala.in

1. Imports and exports

Banks import salary CSVs from companies; shops export GST and sales reports for accountants.

salary.csv→Files.readAllLines→credit 500 accounts

2. Configuration

Apps read settings (database URL, tax rates, feature flags) from files at startup.

app.properties→Files.newBufferedReader→settings

3. Archiving and cleanup

Nightly jobs move old reports into dated folders and delete temporary files older than 30 days.

reports/→Files.move→archive/2026-09/

4. Uploaded documents

KYC PDFs and invoices are saved to a storage folder under a safe generated name, never the name the user sent.

upload→Files.copy(in, dir.resolve(id))→stored

Simplified. Large companies often store such files in cloud object storage, but the read-write-move ideas are the same.

7 Run the code

Create, append, read, delete

import java.io.IOException;
import java.nio.file.*;
import java.util.List;

public class Main {
    public static void main(String[] args) throws IOException {
        Path file = Path.of("data", "orders.csv");
        Files.createDirectories(file.getParent());
        Files.writeString(file, "101,dosa,80\n");
        Files.writeString(file, "102,idli,40\n", StandardOpenOption.APPEND);
        List<String> lines = Files.readAllLines(file);
        System.out.println(lines.size() + " lines: " + lines);
        System.out.println("size " + Files.size(file) + " bytes");
        Files.delete(file);
        System.out.println("exists after delete: " + Files.exists(file));
    }
}
2 lines: [101,dosa,80, 102,idli,40] size 24 bytes exists after delete: false
  • Path.of("data", "orders.csv")Builds data/orders.csv with the right separator for the OS.
  • Files.createDirectories(file.getParent())Make sure the folder exists before writing into it.
  • StandardOpenOption.APPENDAdd to the end; without it the file is replaced.
  • Files.delete(file)Throws if the file is missing; deleteIfExists returns false instead.
8 Line by line

Write, append, read and total

Recorded from the real JVM. The Path and the List of lines appear on the heap; the file itself lives outside the JVM, so watch the notes for what happens on disk.

Worked examples: real problems, solved and traced in memory

Three file tasks from small businesses: saving a list, totalling a CSV, and archiving reports into folders. Each program creates the files it needs, so it runs anywhere.

Example 1Grocery · lists

Save and reload a shopping list

Problem statement

A grocery app saves the customer's list when the app closes and loads it on the next start. Save a List<String> with Files.write, read it back with Files.readAllLines, and show it numbered.

Input
milk, bread, eggs, curd
Expected output
1. milk
2. bread
3. eggs
4. curd
same list? true

Approach

  1. Files.write(path, list) writes each element as one line (UTF-8).
  2. Files.readAllLines(path) gives the list back.
  3. Print with a counter.

Solution: run it live

What happens in memory, step by step

Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.

Example 2Canteen · sales

Total a day's sales from a CSV

Problem statement

Orders are appended to sales.csv as time,item,amount. At closing, read the file, skip the header line, and print the number of orders, the total and the best-selling amount.

Input
header + 4 orders
Expected output
4 orders, total Rs 335, biggest Rs 120

Approach

  1. Write the header once, then append each order line.
  2. Read all lines; start the loop at index 1 to skip the header.
  3. Split each line on commas and parse the amount.

Solution: run it live

What happens in memory, step by step

Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.

Example 3Office · archiving

Archive last month's reports

Problem statement

An office keeps reports in a reports folder. At month end, create archive/2026-09, move every report whose name starts with 2026-09 into it, and list both folders.

Input
reports: 2026-09-gst.txt, 2026-09-sales.txt, 2026-10-sales.txt
Expected output
reports: [2026-10-sales.txt]
archive/2026-09: [2026-09-gst.txt, 2026-09-sales.txt]

Approach

  1. Create the folders with Files.createDirectories.
  2. List the reports folder with Files.list (a stream; close it with try-with-resources).
  3. Files.move each matching file into the archive folder, keeping its name.

Solution: run it live

What happens in memory, step by step

Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.

9 Quiz and revision

Check yourself

Quick revision

Lesson 13.2 in one screen

  • Path names a file; creating one doesn't touch the disk. Files does the work.
  • Relative paths resolve against the working directory (user.dir).
  • writeString/write create or replace; add APPEND to add at the end.
  • readString, readAllLines: whole file into memory, UTF-8 by default.
  • createDirectories before writing into a new folder.
  • copy/move refuse to overwrite unless REPLACE_EXISTING.
  • Errors: NoSuchFileException, FileAlreadyExistsException, all IOException.

Interview and viva questions

What is the difference between File and Path?

Both represent file locations. java.io.File is the original API: many methods return booleans without saying why they failed, and copy/move aren't built in. java.nio.file.Path (Java 7) works with the Files utility class, which offers rich operations, specific exceptions, symbolic-link handling and better performance. New code should use Path and Files.

How do you append to a file in Java?

Files.writeString(path, text, StandardOpenOption.CREATE, StandardOpenOption.APPEND), or new FileWriter(file, true) / new FileOutputStream(file, true).

What is the difference between an absolute and a relative path?

An absolute path starts from the file-system root and always points to the same place. A relative path is resolved against the current working directory, so the same relative path can point to different files depending on where the program was started.

When should you not use Files.readAllLines?

For large files, because it loads every line into memory at once. Read line by line with BufferedReader.readLine() or process Files.lines(path) as a stream, which reads lazily.

How do you safely overwrite a file?

Write the new content to a temporary file in the same folder, then Files.move(tmp, target, REPLACE_EXISTING, ATOMIC_MOVE). Readers then see either the old file or the new one, never a half-written file.

Practice problems

Use Path and Files for everyday file work, plus Scanner and PrintWriter. Every program creates its own files, so the output is fixed. The last three are business tasks.

P1Easy

Write and read a string

Write Welcome to MyPhatshala to welcome.txt with Files.writeString and print it back with Files.readString.

Input
(none)
Expected output
Welcome to MyPhatshala
Show solution and explanation
import java.io.IOException;
import java.nio.file.*;

public class Main {
    public static void main(String[] args) throws IOException {
        Path p = Path.of("welcome.txt");
        Files.writeString(p, "Welcome to MyPhatshala");
        System.out.println(Files.readString(p));
    }
}
Welcome to MyPhatshala

How it works: both methods open, use and close the file for you, with UTF-8. Ideal for small text files.

P2Easy

Exists and size

Check whether notes.txt exists before and after creating it with 5 bytes, and print its size.

Input
(none)
Expected output
before: false
after: true, 5 bytes
Show solution and explanation
import java.io.IOException;
import java.nio.file.*;

public class Main {
    public static void main(String[] args) throws IOException {
        Path p = Path.of("notes.txt");
        System.out.println("before: " + Files.exists(p));
        Files.writeString(p, "hello");
        System.out.println("after: " + Files.exists(p) + ", " + Files.size(p) + " bytes");
    }
}
before: false after: true, 5 bytes

How it works: Files.exists asks the OS; Files.size returns the length in bytes. The program creates notes.txt fresh in its own folder, so “before” is false.

P3Easy

Parts of a path

For the path bills/2026/oct/bill-17.pdf, print the file name, the parent folder and the number of name parts.

Input
bills/2026/oct/bill-17.pdf
Expected output
file:   bill-17.pdf
parent: bills/2026/oct
parts:  4
Show solution and explanation
import java.nio.file.Path;

public class Main {
    public static void main(String[] args) {
        Path p = Path.of("bills", "2026", "oct", "bill-17.pdf");
        System.out.println("file:   " + p.getFileName());
        System.out.println("parent: " + p.getParent());
        System.out.println("parts:  " + p.getNameCount());
    }
}
file: bill-17.pdf parent: bills/2026/oct parts: 4

How it works: a Path is just a name, so this works even though the file doesn't exist. Path.of joins the parts with the right separator for the OS (/ on Linux, \ on Windows).

P4Medium

Count words in a file

Write a two-line review to review.txt, then count its lines and words.

Input
two lines of text
Expected output
2 lines, 8 words
Show solution and explanation
import java.io.IOException;
import java.nio.file.*;
import java.util.List;

public class Main {
    public static void main(String[] args) throws IOException {
        Path p = Path.of("review.txt");
        Files.writeString(p, "Great dosa and fast service\nWill come again\n");
        List<String> lines = Files.readAllLines(p);
        int words = 0;
        for (String line : lines) {
            words += line.trim().split("\\s+").length;
        }
        System.out.println(lines.size() + " lines, " + words + " words");
    }
}
2 lines, 8 words

How it works: split("\\s+") splits on any run of spaces. This is the basis of text analytics: read lines, split, count.

P5Medium

Sum numbers with Scanner

Write the numbers 120 45 300 15 to amounts.txt, then read them with new Scanner(file) and print the sum.

Input
120 45 300 15
Expected output
sum = 480
Show solution and explanation
import java.io.*;
import java.nio.file.*;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) throws IOException {
        Files.writeString(Path.of("amounts.txt"), "120 45\n300 15\n");
        int sum = 0;
        try (Scanner sc = new Scanner(new File("amounts.txt"))) {
            while (sc.hasNextInt()) {
                sum += sc.nextInt();
            }
        }
        System.out.println("sum = " + sum);
    }
}
sum = 480

How it works: a Scanner on a File reads tokens (here ints) across lines, exactly like reading from the keyboard. Close it, as it holds the file open.

P6Medium

Formatted report with PrintWriter

Write a small aligned price table to menu.txt with PrintWriter.printf, then print the file.

Input
dosa 80, thali 120, chai 15
Expected output
dosa     Rs   80
thali    Rs  120
chai     Rs   15
Show solution and explanation
import java.io.*;
import java.nio.file.*;

public class Main {
    public static void main(String[] args) throws IOException {
        String[] items = {"dosa", "thali", "chai"};
        int[] prices = {80, 120, 15};
        try (PrintWriter pw = new PrintWriter("menu.txt")) {
            for (int i = 0; i < items.length; i++) {
                pw.printf("%-8s Rs %4d%n", items[i], prices[i]);
            }
        }
        System.out.print(Files.readString(Path.of("menu.txt")));
    }
}
dosa Rs 80 thali Rs 120 chai Rs 15

How it works: PrintWriter gives you println and printf on a file. %-8s left-aligns in 8 columns; %4d right-aligns numbers. PrintWriter never throws IOException on write; call checkError() if you need to know.

P7Business problem

Attendance from a CSV

attendance.csv has name,status lines (P or A). Count present and absent students and list the absentees.

Input
5 students
Expected output
present 3, absent 2: [Ravi, Joseph]
Show solution and explanation
import java.io.IOException;
import java.nio.file.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws IOException {
        Path p = Path.of("attendance.csv");
        Files.write(p, List.of("Asha,P", "Ravi,A", "Meena,P", "Imran,P", "Joseph,A"));
        int present = 0;
        List<String> absent = new ArrayList<>();
        for (String line : Files.readAllLines(p)) {
            String[] f = line.split(",");
            if (f[1].equals("P")) present++;
            else absent.add(f[0]);
        }
        System.out.println("present " + present + ", absent " + absent.size() + ": " + absent);
    }
}
present 3, absent 2: [Ravi, Joseph]

How it works: CSV is the most common data-exchange format in offices. Reading lines and splitting on commas is enough for simple files; real CSVs with quoted commas need a CSV library.

P8Business problem

Low-stock alert

inventory.csv has item,qty. Write a new file reorder.txt listing items with quantity below 10, then print it.

Input
rice 40, oil 6, sugar 9, salt 25
Expected output
oil (only 6 left)
sugar (only 9 left)
Show solution and explanation
import java.io.IOException;
import java.nio.file.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws IOException {
        Files.write(Path.of("inventory.csv"), List.of("rice,40", "oil,6", "sugar,9", "salt,25"));
        List<String> reorder = new ArrayList<>();
        for (String line : Files.readAllLines(Path.of("inventory.csv"))) {
            String[] f = line.split(",");
            if (Integer.parseInt(f[1]) < 10) reorder.add(f[0] + " (only " + f[1] + " left)");
        }
        Files.write(Path.of("reorder.txt"), reorder);
        System.out.print(Files.readString(Path.of("reorder.txt")));
    }
}
oil (only 6 left) sugar (only 9 left)

How it works: read one file, filter, write another: the shape of most batch jobs. The output file can be emailed to the supplier or loaded by another system.

P9Business problem

Daily backup that may already exist

Copy ledger.txt to ledger-backup.txt. Copying again fails because the backup exists; catch that, then copy with REPLACE_EXISTING.

Input
ledger.txt
Expected output
backup exists: ledger-backup.txt
backup now 32 bytes, ledger 32 bytes
Show solution and explanation
import java.io.IOException;
import java.nio.file.*;

public class Main {
    public static void main(String[] args) throws IOException {
        Path ledger = Path.of("ledger.txt"), backup = Path.of("ledger-backup.txt");
        Files.writeString(ledger, "opening balance 50000\n");
        Files.copy(ledger, backup);
        Files.writeString(ledger, "sale 1200\n", StandardOpenOption.APPEND);
        try {
            Files.copy(ledger, backup);
        } catch (FileAlreadyExistsException e) {
            System.out.println("backup exists: " + e.getFile());
        }
        Files.copy(ledger, backup, StandardCopyOption.REPLACE_EXISTING);
        System.out.println("backup now " + Files.size(backup) + " bytes, ledger " + Files.size(ledger) + " bytes");
    }
}
backup exists: ledger-backup.txt backup now 32 bytes, ledger 32 bytes

How it works: NIO refuses to overwrite by accident: Files.copy throws FileAlreadyExistsException unless you pass REPLACE_EXISTING. Making overwrites explicit prevents losing data.

Real-world scenario questions (asked in company interviews)

File-handling bugs tend to appear only in production, where paths, permissions and sizes differ from your laptop.

Deployment · pathsFresher

Works in the IDE, NoSuchFileException on the server

A report job reads Path.of("config/tax-rates.csv"). It works in IntelliJ, but on the server it fails with NoSuchFileException although the file is deployed in /opt/app/config. Why?

The interviewer is checking: relative paths and the working directory.

Show a strong answer
  • The path is relative; on the server the process starts from a different working directory (e.g. / or the service user's home).
  • Log Path.toAbsolutePath() to confirm, then build paths from a configured base directory (environment variable or config) or load bundled files from the classpath.

Avoid: hard-coding C:\Users\me\... paths.

Batch · memoryJunior

Import job crashes on month-end files

A transaction import uses Files.readAllLines. It works daily, but the month-end file (8 GB) crashes the job with OutOfMemoryError. How would you change it?

The interviewer is checking: streaming large files.

Show a strong answer
  • Read line by line with Files.newBufferedReader or Files.lines (closed in try-with-resources), processing and discarding each line.
  • Write results in batches; keep only running totals in memory.
  • Track the last processed line so a failed run can resume.

Avoid: just raising -Xmx; next month's file will be bigger.

Reliability · crashMid

Half-written settings file after a power cut

A POS terminal saves its settings with Files.writeString(settings, json). After a power cut, the file is half-written and the terminal won't start. How do you make saving safe?

The interviewer is checking: atomic replace.

Show a strong answer
  • Write to settings.json.tmp in the same folder, then Files.move(tmp, settings, REPLACE_EXISTING, ATOMIC_MOVE). The rename is atomic, so the file is always complete.
  • Keep the previous version as a backup and validate on startup, falling back if parsing fails.

Avoid: deleting the old file before writing the new one.

Security · uploadsMid

A filename that escaped the uploads folder

An upload API saves files with uploads.resolve(userGivenName). A tester uploads a file named ../../app/config.properties and overwrites the app's config. Explain and fix.

The interviewer is checking: path traversal.

Show a strong answer
  • .. segments let the resolved path climb out of the uploads folder: a path traversal attack.
  • Never use client file names as paths. Generate an ID (e.g. a UUID) for the stored name and keep the original name as metadata.
  • If you must use it, normalize() the result and check target.startsWith(uploads); also never pass REPLACE_EXISTING for uploads.

Avoid: only stripping the text “../”; there are many encodings of the same trick.