AP COMPUTER SCIENCE A • DATA COLLECTIONS

Using Text Files

Read, parse, and persist structured data beyond a program's runtime using Java file I/O.

Historical Context & Motivation

From the earliest days of computing, programs needed a way to preserve information after execution ended. Before the era of databases and cloud storage, the humble text file served as the primary medium for persisting data—configuration settings, scientific measurements, logs, and user records all lived as sequences of characters on disk. Understanding file I/O is not merely a historical curiosity; it remains a foundational skill because text files are human-readable, portable across operating systems, and require no special software to inspect. Even modern data-processing pipelines frequently begin and end with plain text formats like CSV, JSON, and TSV, making the ability to read from and write to files a prerequisite for virtually every domain of software engineering.

1956
IBM 305 RAMAC
The first commercial hard disk drive introduced random-access storage, enabling programs to read and write persistent data files rather than relying exclusively on sequential tape.
1969
Unix & the File Abstraction
Unix established the paradigm that 'everything is a file,' unifying access to devices, pipes, and data under a single I/O interface that influenced every major language, including Java.
1995
Java 1.0 — java.io
Java's original I/O library shipped with stream-based classes like FileReader and BufferedReader, giving developers a platform-independent way to handle text files.
2004
Java 5 — Scanner
The Scanner class simplified tokenized parsing of text input, quickly becoming the preferred tool in educational settings and the AP Computer Science A curriculum.
2014
Java 8 — Streams & NIO
The introduction of Files.lines() and the Stream API allowed declarative, memory-efficient file processing—though the AP exam still centers on Scanner-based approaches.

The central question that text-file I/O addresses is deceptively simple: how does a program move structured data between volatile memory and persistent storage while keeping that data accessible to both humans and other programs? Answering this question requires understanding file paths, character encoding, buffered reading, parsing tokens, and the crucial practice of resource management—topics we explore in the sections that follow.

Core Principles & Definitions

Working with text files in Java revolves around a small set of interconnected ideas. Each principle builds on the last: you must locate a file before you can open it, open it before you can read tokens, and close it before your program terminates cleanly. The following grid distills these foundational concepts.

1

File Path & the File Object

A File object (from java.io.File) represents a path on disk. It does not open or read the file; it simply describes where the file is. Use relative paths (e.g., "data/scores.txt") for portability.
2

Scanner for Reading

The Scanner class (from java.util.Scanner) wraps an input source and breaks it into tokens delimited by whitespace or a custom pattern. Methods like nextLine(), nextInt(), and nextDouble() parse the next token into the desired type.
3

hasNext Guards

Before calling a next*() method, you should verify data remains with hasNext(), hasNextLine(), or hasNextInt(). This prevents a NoSuchElementException at runtime.
4

FileNotFoundException

Constructing a Scanner on a File that does not exist throws a checked FileNotFoundException. Java forces you to handle it—either with a try-catch block or by declaring throws FileNotFoundException on the enclosing method.
5

Resource Cleanup

An open file holds an operating-system resource. Always call scanner.close() when finished, or use a try-with-resources statement to guarantee automatic cleanup even if an exception is thrown.
KEY TAKEAWAY
Think of a text file as a book in a library. The File object is the call number that locates the book on the shelf; the Scanner is the reader who opens the book and moves a finger line by line; and closing the Scanner is like returning the book so other patrons—or other parts of your program—can access it.

Visual Explanation — The File-Reading Pipeline

The diagram below traces the complete lifecycle of reading a text file in Java, from the file system through the Scanner and into your program's data structures. Follow the arrows to see how raw bytes on disk become usable Java objects in memory.

The pipeline flows left to right: a File object locates the file on disk; a Scanner reads and tokenizes lines; parsed values are stored in Java collections in memory; and the Scanner is closed to release the resource.

Notice that the Scanner sits at the center of the pipeline. It acts as a translator: on its left side it consumes a stream of characters from disk, and on its right side it emits typed Java values—Strings, ints, doubles—ready for storage in arrays or ArrayList structures. The lifecycle summary at the bottom of the diagram is the pattern you will use in virtually every file-reading method you write for the AP exam: create, open, read, store, close.

How It Works — Reading and Writing Code Patterns

Java's approach to file I/O is built on the principle of wrapping: you wrap a File object inside a Scanner to read, or inside a PrintWriter to write. This section presents the essential code patterns you will encounter on the AP Computer Science A exam, focusing on the Scanner-based reading pattern, followed by a brief discussion of writing with PrintWriter.

Pattern 1 — Reading Line by Line

The most common file-reading idiom uses a while loop guarded by hasNextLine(). On each iteration the loop calls nextLine() to retrieve one full line of text, which can then be split, parsed, or stored directly. This pattern is robust because it gracefully handles files of any length—including empty files, where the while condition is immediately false.

LINE-BY-LINE READING PATTERN
Scanner sc = new Scanner(new File("data.txt")); while (sc.hasNextLine()) { String line = sc.nextLine(); // process line } sc.close();
new File("data.txt") creates the path reference. hasNextLine() returns true while unread lines remain. nextLine() consumes and returns the next full line (up to but not including the newline character).

Pattern 2 — Reading Token by Token

When a file's data is whitespace-delimited (spaces, tabs, or newlines), you can use hasNext() with next() to read one token at a time, or hasNextInt() / nextInt() to read typed values. This is convenient when each token is a discrete datum, such as a list of integers or a name-score pair on each line.

TOKEN-BY-TOKEN READING PATTERN
Scanner sc = new Scanner(new File("scores.txt")); while (sc.hasNext()) { String name = sc.next(); int score = sc.nextInt(); // process name, score } sc.close();
next() reads the next whitespace-delimited String token. nextInt() reads the next token and parses it as an int. If the token is not an integer, an InputMismatchException is thrown.

Pattern 3 — Writing with PrintWriter

While the AP exam focuses primarily on reading, understanding writing solidifies the concept. A PrintWriter wraps a File and provides familiar print(), println(), and printf() methods. Like Scanner, it must be closed to flush and release resources. If the file does not exist, PrintWriter creates it; if it does exist, the file is overwritten unless you specifically append.

WRITING PATTERN
PrintWriter pw = new PrintWriter(new File("output.txt")); pw.println("Alice 95"); pw.println("Bob 87"); pw.close();
println() writes a line of text followed by a system-dependent newline. Always call close() to ensure all buffered data is actually written to disk.
⚠️ Exception Handling Reminder
Both new Scanner(new File(...)) and new PrintWriter(new File(...)) throw a checked FileNotFoundException. On the AP exam, the simplest approach is to add throws FileNotFoundException to your method signature. In production code, a try-catch block or try-with-resources is preferred.

Parsing Strategies & Data Formats

Reading raw lines from a file is only half the battle. The other half involves parsing those lines into meaningful data. The strategy you choose depends on how the file is formatted. Below is a visual taxonomy of the most common text-file formats you will encounter on the AP exam and in real-world applications, followed by a detailed table.

The decision tree helps you choose the right parsing strategy based on the file's delimiter. CSV files use split(","); whitespace-delimited files let Scanner do the work; fixed-width files rely on substring().
Common text file formats and their corresponding Java parsing strategies
FormatDelimiterJava Parsing ApproachWhen to Use
WhitespaceSpaces / tabs / newlinesScanner.next(), nextInt(), etc.Simple name-value pairs, integer lists
CSVComma (",")line.split(",") → String array, then Integer.parseInt()Spreadsheet exports, multi-field records
TSVTab ("\t")line.split("\t") → same strategy as CSVWhen data fields contain commas
One item per lineNewlineScanner.nextLine() in a while loopWord lists, log entries, sentences

Worked Example — Reading a CSV Into an ArrayList

Suppose you have a file called students.csv containing one record per line in the format name,gradeLevel,gpa. Your task is to read the file, store all student names with a GPA above 3.5 into an ArrayList<String>, and print the result. The file contents are:

SAMPLE FILE: students.csv
Alice,12,3.9 Bob,11,3.2 Carol,12,3.7 Dave,10,2.8 Eve,11,3.6
Five records, each with a name (String), grade level (int), and GPA (double).
Filtering Students by GPA from a CSV File
1
Step 1 — Import Required ClassesYou need java.io.File, java.io.FileNotFoundException, java.util.Scanner, and java.util.ArrayList. Declare your method with throws FileNotFoundException since Scanner's File constructor throws a checked exception.
public static void main(String[] args) throws FileNotFoundException
2
Step 2 — Open the File with ScannerCreate a File object pointing to "students.csv", then wrap it in a Scanner. Also initialize the ArrayList that will hold the results.
Scanner sc = new Scanner(new File("students.csv")); ArrayList<String> honors = new ArrayList<String>();
3
Step 3 — Loop and Parse Each LineUse a while (sc.hasNextLine()) loop. Inside, call sc.nextLine() to get the entire line as a String, then line.split(",") to break it into a String array of three parts. Parse the GPA with Double.parseDouble(parts[2]).
String[] parts = line.split(","); → for the first line, parts = ["Alice", "12", "3.9"]
4
Step 4 — Apply the Filter ConditionCheck whether the parsed GPA exceeds 3.5. If so, add parts[0] (the name) to the honors ArrayList.
if (Double.parseDouble(parts[2]) > 3.5) { honors.add(parts[0]); }
5
Step 5 — Close Scanner and Output ResultsAfter the loop, close the Scanner to release the file handle. Then print the ArrayList. The expected output contains Alice (3.9), Carol (3.7), and Eve (3.6).
sc.close();honors = [Alice, Carol, Eve]

The complete method is shown below for reference. Notice how concise the code is—barely ten lines of logic—yet it demonstrates every principle from Sections 2 through 5: creating a File, opening a Scanner, guarding with hasNextLine(), splitting a CSV line, converting types, filtering into a collection, and closing the resource.

COMPLETE METHOD
public static void main(String[] args) throws FileNotFoundException { Scanner sc = new Scanner(new File("students.csv")); ArrayList<String> honors = new ArrayList<String>(); while (sc.hasNextLine()) { String line = sc.nextLine(); String[] parts = line.split(","); double gpa = Double.parseDouble(parts[2]); if (gpa > 3.5) { honors.add(parts[0]); } } sc.close(); System.out.println(honors); }
Output: [Alice, Carol, Eve]

Strengths, Limitations & Common Pitfalls

Text files are a powerful and flexible data storage mechanism, but they are not without trade-offs. The table below contrasts the advantages of text-file I/O with its limitations, helping you decide when a text file is the right tool for the job—and when you should consider alternatives.

Strengths vs. limitations of text file I/O
StrengthsLimitations
Human-readable: you can open and inspect files in any text editor.No built-in structure: you must write your own parsing logic for each format.
Platform-independent: text files work across Windows, macOS, and Linux.Slow for large data: sequential reading is O(n) and lacks random access.
No special software required: no database engine, no binary decoder.No type safety: all data is stored as characters and must be explicitly parsed.
Easy to produce: PrintWriter, System.out redirection, or even manual editing.Delimiter conflicts: commas in CSV data can break naïve split() calls.
Great for small-to-medium datasets, configuration, and logging.No concurrent access control: multiple writers can corrupt the file.

Common Pitfalls on the AP Exam

  • Forgetting to handle FileNotFoundException — This is a checked exception. If you neither catch it nor declare it, the code will not compile.
  • Mixing nextLine() with nextInt() — After nextInt(), the newline character remains in the buffer. A subsequent nextLine() reads an empty string. Consume the leftover newline with an extra nextLine() call.
  • Not closing the Scanner — While this may not crash a small program, it leaks OS resources and is considered a defect.
  • Off-by-one with split() — Remember that split(",") returns an array whose indices start at 0. If a line has 3 fields, the valid indices are 0, 1, and 2.
KEY TAKEAWAY
Think of text-file I/O like handwritten lab notes versus a digital database. Lab notes are universally readable and require no special tool, but they lack automatic indexing and error checking. Just as a scientist must carefully label and organize notebook pages, a Java programmer must carefully parse, validate, and close file resources. The simplicity of text files is both their greatest strength and their most common source of bugs.

Connection to Advanced Topics

The Scanner-based file reading you learn in AP Computer Science A is the entry point to a much larger ecosystem of I/O techniques. As you advance, you will encounter buffered streams, character encodings, binary file formats, and entire frameworks for serializing objects. The table below maps AP-level concepts to their more advanced counterparts.

AP concepts and their advanced counterparts
AP-Level ConceptAdvanced CounterpartWhy It Matters
Scanner for file readingBufferedReader + Files.lines() (Java NIO)Streams enable lazy, memory-efficient processing of massive files.
PrintWriter for file writingBufferedWriter + Files.write()Buffered writers are significantly faster for high-throughput logging and data export.
CSV parsing with split()Libraries like Apache Commons CSV, Jackson CSVHandle edge cases (quoted fields, embedded commas) that naïve splitting cannot.
Flat text filesJSON, XML, Protocol Buffers, databasesStructured formats support nesting, schema validation, and efficient querying.
scanner.close() manuallytry-with-resources (AutoCloseable)Guarantees cleanup even when exceptions occur; standard in production code.

Mastering the fundamentals covered here—opening a resource, iterating through data, parsing tokens, and closing the resource—establishes a mental model that transfers directly to these advanced APIs. The specific class names change, but the underlying lifecycle pattern remains remarkably consistent across Java's entire I/O library and, indeed, across most programming languages.

Practice Problems

1
Which of the following best explains why FileNotFoundException is a checked exception in Java?
2
Consider the file nums.txt containing: 10 20 30 What is the output of the following code? Scanner sc = new Scanner(new File("nums.txt")); int sum = 0; while (sc.hasNextInt()) { sum += sc.nextInt(); } System.out.println(sum); sc.close();
3
A file data.csv contains: red,5 blue,12 green,8 Consider the following code segment: Scanner sc = new Scanner(new File("data.csv")); ArrayList<String> result = new ArrayList<String>(); while (sc.hasNextLine()) { String line = sc.nextLine(); String[] parts = line.split(","); if (Integer.parseInt(parts[1]) > 6) { result.add(parts[0]); } } sc.close(); System.out.println(result); What is printed?
PROBLEM 4APPLIED
A text file temps.txt contains one double value per line representing daily high temperatures in degrees Fahrenheit. Write a static method averageTemp that takes a String parameter filename, reads all the temperatures from the file, and returns the average as a double. If the file is empty, return 0.0. You may assume the file exists.
PROBLEM 5CRITICAL THINKING
A school stores student records in a file roster.csv with the format lastName,firstName,gradeLevel,gpa (one record per line, no header row). Write a class RosterAnalyzer with the following: (a) A static method getHonorRoll(String filename, double minGPA) that returns an ArrayList<String> of full names (formatted as "firstName lastName") for all students whose GPA is at least minGPA. (b) A static method writeHonorRoll(String inputFile, String outputFile, double minGPA) that calls getHonorRoll and writes each name on a separate line to outputFile using a PrintWriter.

Summary

Text-file I/O in Java follows a consistent lifecycle: create a File object to locate the file on disk, wrap it in a Scanner to read and tokenize its contents, guard every read with hasNext-family methods to avoid exceptions, parse tokens into typed values using methods like Integer.parseInt() or Double.parseDouble(), store results in collections such as ArrayList, and always close the Scanner to release OS resources.

For files with comma-separated values, the split(",") method breaks each line into a String array, after which individual fields are accessed by index and converted as needed. The FileNotFoundException is a checked exception that must be declared or caught—Java's way of ensuring you plan for the real-world possibility that a file may not exist. Writing files mirrors reading: wrap a File in a PrintWriter, use println(), and close when done. Mastering these patterns equips you both for the AP exam and for the data-driven programming challenges that lie ahead.

Varsity Tutors • AP Computer Science A • Using Text Files