4.06 Using Text Files
Read and process text files with Java, handle lines of input, and close file resources safely.
4.6 — Using Text Files
AP CSA · Unit 4: Data Collections
A school club has saved its attendance numbers. How can a Java program use those numbers tomorrow without someone typing them again?
Learning targets
By the end, you can connect a text file to a Scanner, choose the right reading method, trace a file-reading loop, and separate a simple delimited line into fields.
Before you start: variables, while loops, arrays, and String methods.
Try it: Predict the answer, record your work in your notes, and compare with a partner. Open each answer reveal after attempting the activity.
Your mission and learning path
You are the club secretary. Turn yesterday’s attendance file into a report that helps the club plan enough seats.
Start with your experience: Would a filename, a Scanner, and the next number in a file all hold the same information? Tell a partner what you expect before running anything.
Success looks like: You read each integer once, handle an empty file, close the scanner, and justify your test results.
| Learning design step | What you do | Evidence you keep |
|---|---|---|
| Understand the learner | Compare your prediction with a partner’s. Name what feels confusing. | One question in your notes |
| Define the goal | Read the success criteria and pick the skill you need to practice. | A specific goal |
| Try a small solution | Run an example, change one input, and predict the effect. | Before/after output |
| Test your idea | Attempt the popcorn task, then use the homework checks. | Expected versus actual results |
| Get feedback and revise | Have a partner try one new input. Explain and fix any mismatch. | One comment, your change, and the rerun |
Suggested pace: 5 minutes to predict, 15 to explore, 10 for partner practice, and 5 for the exit ticket; finish the homework afterward.
Using the runners: Click Run below a challenge. Each editor is a separate complete Java program; it does not remember variables from another editor. Edit the code, then run again. Use Copy Code to keep your work. In a Java notebook, keep the final ClassName.main(null); call; in a .java file, remove that final call and run the class normally.
1. Warm-up: data that lasts
Imagine int attendance = 24; exists while your program runs. The program ends. Tomorrow it starts again.
- Does that variable automatically remember yesterday’s value?
- How would saving
24in a text file help? - Is a filename the same thing as the contents of a file?
Check your reasoning
- No. A local variable does not automatically preserve its value between program runs.
- The file can remain on storage after the program exits. A later run can read it.
- No. A filename/path tells Java where to look; the contents are the data stored there.
2. Read an attendance file
For optional execution, save this data as attendance.txt in your Java program’s working directory (the directory from which it runs). That is not always the folder containing the source file.
18 24
21 17
Save the complete program below as AttendanceReader.java.
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
public class AttendanceReader {
public static void main(String[] args) throws IOException {
File attendanceFile = new File("attendance.txt");
Scanner input = new Scanner(attendanceFile);
int total = 0;
int days = 0;
while (input.hasNext()) {
int students = input.nextInt();
total += students;
days++;
}
input.close();
System.out.println("Days: " + days);
System.out.println("Total: " + total);
}
}
Walk through it together:
Filerepresents the path. Creating theFileobject does not create a missing file or read its contents.Scanneropens that file for reading. Here we promise the file contains only valid integer tokens.hasNext()checks whether another token exists; it does not consume it or verify that it is an integer.nextInt()consumes one integer token. Spaces and line breaks separate tokens.throws IOExceptionlets file-opening failures propagate to the caller. It does not repair a missing file; if uncaught in this program, the failure stops execution.close()releases the scanner’s resources when reading is complete.
Think about it: Point to the exact statement that moves the scanner forward. What happens if we remove it but leave the loop condition?
Check your reasoning
input.nextInt() consumes input. Without any consuming read inside the loop, hasNext() keeps reporting the same available token, so a nonempty file can cause an infinite loop.
Run the attendance report
Predict the output before clicking Run: Days: 4, Total: 80. Adding 30 should produce Days: 5, Total: 110.
The supplied sampleFile helper writes a real temporary file on the runner’s computer, then the program reads it with Scanner(File). This setup makes the demo independent of files on your laptop. File-writing setup is provided for testing; the skill to practice is reading the file. For a local file, replace sampleFile(...) with new File("attendance.txt") after creating that file yourself. A Scanner constructed from a String would scan the String’s contents, not open a file.
Code Runner Challenge
Predict days and total, then append 30 to the sample and rerun.
View IPYNB Source
// CODE_RUNNER: Predict days and total, then append 30 to the sample and rerun.
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Scanner;
public class AttendanceLab {
// Supplied test setup: creates a real temporary text file for this run.
public static File sampleFile(String text) throws IOException {
File file = File.createTempFile("csa-attendance-", ".txt");
file.deleteOnExit();
PrintWriter writer = new PrintWriter(file);
writer.print(text);
writer.close();
return file;
}
public static void main(String[] args) throws IOException {
File file = sampleFile("18 24\n21 17\n");
Scanner input = new Scanner(file);
int days = 0;
int total = 0;
while (input.hasNext()) {
int students = input.nextInt();
total += students;
days++;
}
input.close();
System.out.println("Days: " + days);
System.out.println("Total: " + total);
}
}
AttendanceLab.main(null);
3. Partner activity: be the scanner
One partner points to the next unread token. The other updates the variables. Swap roles after two iterations.
Predict: Does the line break after 24 change the total?
| Iteration | Token consumed | total after addition | days after increment |
|---|---|---|---|
| 1 | 18 | … | … |
| 2 | 24 | … | … |
| 3 | 21 | … | … |
| 4 | 17 | … | … |
Check your reasoning
| Iteration | Token | total | days |
|---|---|---|---|
| 1 | 18 | 18 | 1 |
| 2 | 24 | 42 | 2 |
| 3 | 21 | 63 | 3 |
| 4 | 17 | 80 | 4 |
The output is Days: 4 followed by Total: 80. The newline separates tokens just like a space here. After the fourth read, hasNext() is false.
Change the input: An empty file produces Days: 0 and Total: 0. A file containing 18 absent 21 fails at nextInt() when the next token is absent; hasNext() alone does not guarantee a numeric token.
Your response
- My predicted total:
- The statement that consumes data:
- What changes if I add
30on a new line: - My explanation of the empty-file result:
4. Choose the reading method
Each row below is an independent reading situation; assume the scanner is at the start of the shown input.
| Input | What you want | Method | Result type |
|---|---|---|---|
24 |
One integer | nextInt() |
int |
3.5 |
One decimal value | nextDouble() |
double |
true |
One Boolean value | nextBoolean() |
boolean |
Robotics Club |
The first word | next() |
String |
Robotics Club |
The whole line | nextLine() |
String |
| Any remaining token | Whether something is available | hasNext() |
boolean |
Quick vote: A club name contains spaces. Should we read the name with next() or nextLine()? Explain the information we lose with the other choice.
For this lesson, use separate scanners/examples for token reading and line reading. Mixing nextLine() with token-reading methods on one input source is outside the specified AP exam scope for this topic.
Turn one line into fields
Suppose clubs.txt has exactly these two nonblank lines, with one comma per line and no embedded commas:
Robotics,Room 12
Art,Room 8
Inside a method declared with throws IOException, and with the earlier imports:
Scanner clubs = new Scanner(new File("clubs.txt"));
while (clubs.hasNext()) {
String line = clubs.nextLine();
String[] fields = line.split(",");
System.out.println(fields[0] + " meets in " + fields[1]);
}
clubs.close();
split(",") creates a String array. Array indexing still starts at zero. This example assumes every line follows the two-field format; arbitrary CSV files can be more complicated.
Predict: What is fields.length for the first record? What is printed?
Check your reasoning
fields.length is 2. The two output lines are:
Robotics meets in Room 12
Art meets in Room 8
The name example needs nextLine(): next() would return only Robotics. The club loop uses only line reads; hasNext() checks availability without consuming input. Its stated nonblank, consistently formatted input makes this pattern suitable here.
Code Runner Challenge
Predict both lines, then change a club name to include spaces.
View IPYNB Source
// CODE_RUNNER: Predict both lines, then change a club name to include spaces.
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Scanner;
public class ClubFileLab {
// Supplied test setup: creates a real temporary text file for this run.
public static File sampleFile(String text) throws IOException {
File file = File.createTempFile("csa-attendance-", ".txt");
file.deleteOnExit();
PrintWriter writer = new PrintWriter(file);
writer.print(text);
writer.close();
return file;
}
public static void main(String[] args) throws IOException {
File file = sampleFile("Robotics Club,Room 12\nArt Club,Room 8\n");
Scanner input = new Scanner(file);
while (input.hasNext()) {
String[] fields = input.nextLine().split(",");
System.out.println(fields[0] + " meets in " + fields[1]);
}
input.close();
}
}
ClubFileLab.main(null);
5. Debug before you code
A classmate writes this loop for a file of integers:
while (input.hasNext()) {
input.nextInt();
total += input.nextInt();
}
Talk through 18 24 21 17. Which values contribute to total? What if a fifth value is appended?
Check your reasoning
The first read in each iteration discards a number. Only 24 and 17 are added, for 41. With an odd number of tokens, the final iteration consumes the last token with the first call and then tries to read past the end with the second call. Fix this by reading once into a variable and using that variable.
6. Popcorn hack: count busy days
Write a method countBusyDays(String filename) throws IOException that returns how many integers in a file are at least 20.
Contract: The file exists, contains only valid integer tokens, and may be empty. Read every token once. Close the scanner. Do not assume a fixed number of days.
Use the imports from the complete program and place this method inside a class.
public static int countBusyDays(String filename) throws IOException {
// Open a scanner.
// Count values >= 20.
// Close the scanner and return the count.
}
| File contents | Expected return |
|---|---|
18 24 21 17 |
2 |
20 |
1 |
19 0 |
0 |
| Empty file | 0 |
Reveal a solution after writing yours
public static int countBusyDays(String filename) throws IOException {
Scanner input = new Scanner(new File(filename));
int busyDays = 0;
while (input.hasNext()) {
int attendance = input.nextInt();
if (attendance >= 20) {
busyDays++;
}
}
input.close();
return busyDays;
}
Self-check: Did you open the provided filename, consume one value per iteration, include exactly 20, close the scanner, and return zero for an empty file?
Code Runner Challenge
Complete countBusyDays, then check the boundary value 20 and an empty file.
View IPYNB Source
// CODE_RUNNER: Complete countBusyDays, then check the boundary value 20 and an empty file.
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Scanner;
public class BusyDaysPractice {
// Supplied test setup: creates a real temporary text file for this run.
public static File sampleFile(String text) throws IOException {
File file = File.createTempFile("csa-attendance-", ".txt");
file.deleteOnExit();
PrintWriter writer = new PrintWriter(file);
writer.print(text);
writer.close();
return file;
}
public static int countBusyDays(String filename) throws IOException {
// TODO: Open a Scanner, read each integer once, count values >= 20,
// close the Scanner, and return the count.
return -1;
}
public static void main(String[] args) throws IOException {
String[] data = {"18 24 21 17", "20", "19 0", ""};
int[] expected = {2, 1, 0, 0};
for (int i = 0; i < data.length; i++) {
int actual = countBusyDays(sampleFile(data[i]).getPath());
System.out.println((actual == expected[i] ? "PASS" : "FAIL")
+ " case " + i + ": expected " + expected[i] + ", actual " + actual);
}
}
}
BusyDaysPractice.main(null);
Your solution
// Write countBusyDays here.
My trace for the boundary value 20:
One test I would add and its expected result:
7. Exit ticket
Answer individually before opening the key.
- What is the difference between
hasNext()andnextInt()? - Why might
new Scanner(new File("attendance.txt"))fail even when the code compiles? - Given
String record = "Meryl,Blue";, what doesrecord.split(",")[1]produce?
Exit-ticket key
hasNext()checks availability without advancing.nextInt()consumes a token as an integer and can fail if the token is invalid or unavailable.- The path may not locate a readable file in the working directory.
- The String
"Blue".
Homework: plan seats from the saved report
The club wants the total attendance on busy days, not just the number of busy days. Implement totalAtLeast(filename, threshold): add only values greater than or equal to the threshold. Use File and Scanner, consume each integer once, and close the scanner. Assume the file contains valid nonnegative integers and the sum fits in an int.
Before coding, trace 18 24 21 17 with threshold 20: the selected numbers are 24 and 21, so the total is 45. Explain why 2 would answer a different question. The starter compiles but intentionally prints FAIL until you implement the method. Do not change the expected values to make a test pass.
Code Runner Challenge
Write totalAtLeast and run all five checks; then add your own test.
View IPYNB Source
// CODE_RUNNER: Write totalAtLeast and run all five checks; then add your own test.
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Scanner;
public class AttendanceHomework {
// Supplied test setup: creates a real temporary text file for this run.
public static File sampleFile(String text) throws IOException {
File file = File.createTempFile("csa-attendance-", ".txt");
file.deleteOnExit();
PrintWriter writer = new PrintWriter(file);
writer.print(text);
writer.close();
return file;
}
public static int totalAtLeast(String filename, int threshold) throws IOException {
// TODO: Return the SUM of attendance values >= threshold, not their count.
// The file exists, has only valid nonnegative integers, and may be empty.
return -1;
}
public static void main(String[] args) throws IOException {
String[] data = {"18 24 21 17", "20", "19 0", "", "20\n20 21"};
int[] thresholds = {20, 20, 20, 20, 20};
int[] expected = {45, 20, 0, 0, 61};
for (int i = 0; i < data.length; i++) {
int actual = totalAtLeast(sampleFile(data[i]).getPath(), thresholds[i]);
System.out.println((actual == expected[i] ? "PASS" : "FAIL")
+ " case " + i + ": expected " + expected[i] + ", actual " + actual);
}
}
}
AttendanceHomework.main(null);
Publish your homework and check it as a student
- In your own portfolio, create
_notebooks/homework/2026-09-21-4-6-homework.ipynb. Choose a Java kernel. Copy your completed homework runner into a code cell, including the imports, class, and finalmain(null)call. - Add a raw cell first with the template below. Replace
your-github-idandYour Name; keep your own unique permalink.
---
layout: post
title: "4.6 Homework"
description: "My predictions, Java solution, test results, and revision."
author: Your Name
categories: [Java, Homework]
lesson_language: Java
codemirror: true
permalink: /homework/your-github-id/4-6/
---
- Add Markdown sections named Prediction, Solution, Tests, and Feedback and revision. Include a trace of one file, explain why the empty file returns zero, and identify the line that advances the scanner.
- Run all cells from a fresh kernel. Keep the printed output. Include the supplied checks and one test you designed, with expected and actual results. Fix failing checks before submitting.
- Commit and publish in your portfolio. Open the published homework page and run its editor again. Check that the code, outputs/evidence, and your name are visible. If you get a 404, check the build and the exact permalink before submitting.
- Use the lesson’s submission form when available: sign in, paste your published homework URL, and include the evidence below. If your class uses a different submission destination, use the one your teacher provides. Do not submit the lesson’s URL as your homework.
Lesson: 4.6
Homework URL:
Popcorn result:
Supplied checks passed / total:
My extra test: input / expected / actual
Partner feedback:
What I changed and the rerun result:
Self-check rubric (1 point): popcorn work with reasoning 0.2; completed homework and explanation 0.4; supplied tests plus your own boundary test 0.2; working published link and feedback/revision evidence 0.2. These are the lesson’s proposed criteria; follow any changes your teacher gives you.
If every check already passes, revise an explanation or add a stronger test after peer feedback. Report what actually happened; do not invent a peer review or a test result.
References and next steps
- College Board AP Computer Science A Course and Exam Description, effective fall 2025 — Topic 4.6; use the topic heading to find the learning objectives and exam scope.
- Oracle: Scanner — file constructor and token/line methods.
- Oracle: File — file paths and the supplied temporary-file helper.
- Java lesson catalog — return to the class’s lesson collection.
Submit Assignment
Need to update a submission later? Open the submissions dashboard.