Loading
Read, parse, and persist structured data beyond a program's runtime using Java file I/O.
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.
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.
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.
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.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.next*() method, you should verify data remains with hasNext(), hasNextLine(), or hasNextInt(). This prevents a NoSuchElementException at runtime.try-catch block or by declaring throws FileNotFoundException on the enclosing method.try-with-resources statement to guarantee automatic cleanup even if an exception is thrown.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.
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.
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.
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.
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).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.
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.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.
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.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.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.
split(","); whitespace-delimited files let Scanner do the work; fixed-width files rely on substring().| Format | Delimiter | Java Parsing Approach | When to Use |
|---|---|---|---|
| Whitespace | Spaces / tabs / newlines | Scanner.next(), nextInt(), etc. | Simple name-value pairs, integer lists |
| CSV | Comma (",") | line.split(",") → String array, then Integer.parseInt() | Spreadsheet exports, multi-field records |
| TSV | Tab ("\t") | line.split("\t") → same strategy as CSV | When data fields contain commas |
| One item per line | Newline | Scanner.nextLine() in a while loop | Word lists, log entries, sentences |
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:
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"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>();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"]parts[0] (the name) to the honors ArrayList.if (Double.parseDouble(parts[2]) > 3.5) { honors.add(parts[0]); }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.
[Alice, Carol, Eve]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 | Limitations |
|---|---|
| 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. |
nextInt(), the newline character remains in the buffer. A subsequent nextLine() reads an empty string. Consume the leftover newline with an extra nextLine() call.split(",") returns an array whose indices start at 0. If a line has 3 fields, the valid indices are 0, 1, and 2.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-Level Concept | Advanced Counterpart | Why It Matters |
|---|---|---|
Scanner for file reading | BufferedReader + Files.lines() (Java NIO) | Streams enable lazy, memory-efficient processing of massive files. |
PrintWriter for file writing | BufferedWriter + Files.write() | Buffered writers are significantly faster for high-throughput logging and data export. |
CSV parsing with split() | Libraries like Apache Commons CSV, Jackson CSV | Handle edge cases (quoted fields, embedded commas) that naïve splitting cannot. |
| Flat text files | JSON, XML, Protocol Buffers, databases | Structured formats support nesting, schema validation, and efficient querying. |
scanner.close() manually | try-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.
FileNotFoundException is a checked exception in Java?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();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?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.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.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.
Keep learning with more lessons from the same subject.