Introduction
So far, we've worked with data created directly in our programs—values assigned to variables or stored in arrays using initializer lists. But real programs often need to work with external data stored in files. Topic 4.6 introduces reading data from text files.
A file is storage for data that persists when the program is not running. Unlike variables that disappear when your program ends, data in files remains saved on disk. The data in a file can be retrieved during program execution, allowing programs to process large datasets, load configurations, or import information from external sources.
This topic covers the File and Scanner classes for reading text files, handling potential errors with IOException, and processing file contents using various Scanner methods.
Why Use Files?
Files solve several problems:
Persistence: Data survives after the program ends. Save a game state, configuration settings, or user preferences to reload later.
Large datasets: Process thousands or millions of data points without manually typing them into your code.
External data sources: Import data from spreadsheets, databases, or other programs.
Separation of data and code: Update data without recompiling your program.
File and Scanner Classes
A file can be connected to the program using the File and Scanner classes.
Opening a File
A file can be opened by creating a File object, using the name of the file as the argument of the constructor.
File constructor:
- File(String str) — creates a File object where str is the pathname for the file
Example:
File inputFile = new File("data.txt");This creates a File object representing the file "data.txt" in the same directory as your program.
Creating a Scanner for File Input
Once you have a File object, create a Scanner to read from it:
Scanner constructor for files:
- Scanner(File f) — creates a Scanner that reads from the specified File
Example:
File inputFile = new File("scores.txt");
Scanner fileScanner = new Scanner(inputFile);Import Statements and IOException
Required Imports
The File and IOException classes are part of the java.io package. An import statement must be used to make these classes available for use in the program.
import java.io.File;
import java.io.IOException;Or import the entire package:
import java.io.*;The Scanner class is in java.util:
import java.util.Scanner;Handling IOException
When using the File class, it is required to indicate what to do if the file with the provided name cannot be opened. One way to accomplish this is to add throws IOException to the header of the method that uses the file.
import java.io.*;
import java.util.Scanner;
public class FileReader
{
public static void readFile() throws IOException
{
File inputFile = new File("data.txt");
Scanner scan = new Scanner(inputFile);
// Read from file...
scan.close();
}
}If the file name is invalid (file doesn't exist, wrong path, etc.), the program will terminate with an error message.
Scanner Methods for Reading Files
The following Scanner methods work with files just like they work with other input sources:
Reading Primitive Types
int nextInt() — returns the next int from the file. If the next value isn't a valid int or doesn't exist, throws InputMismatchException.
double nextDouble() — returns the next double from the file. If the next value isn't a valid double or doesn't exist, throws InputMismatchException.
boolean nextBoolean() — returns the next boolean from the file. If the next value isn't a valid boolean or doesn't exist, throws InputMismatchException.
Example file numbers.txt:
Reading code:
File f = new File("numbers.txt");
Scanner scan = new Scanner(f);
int num = scan.nextInt(); // 42
double decimal = scan.nextDouble(); // 3.14
boolean flag = scan.nextBoolean(); // true
scan.close();Reading Strings
String nextLine() — returns the next line of text as a String. Can return an empty string if the line is blank.
String next() — returns the next whitespace-delimited String (reads until space, tab, or newline).
Example file words.txt:
Reading with next():
Scanner scan = new Scanner(new File("words.txt"));
String w1 = scan.next(); // "Hello"
String w2 = scan.next(); // "World"
String w3 = scan.next(); // "Java"
String w4 = scan.next(); // "Programming"
scan.close();Reading with nextLine():
Scanner scan = new Scanner(new File("words.txt"));
String line1 = scan.nextLine(); // "Hello World"
String line2 = scan.nextLine(); // "Java Programming"
scan.close();Checking for More Data
boolean hasNext() — returns true if there is a next item to read in the file; returns false otherwise.
This is essential for processing files of unknown length.
Closing Files
void close() — closes the scanner and releases file resources.
A file should be closed when the program is finished using it. Always call close() when done reading.
Reading Files with While Loops
A while loop can be used to detect if the file still contains elements to read by using the hasNext() method as the condition of the loop.
File f = new File("data.txt");
Scanner scan = new Scanner(f);
while (scan.hasNext())
{
String data = scan.next();
System.out.println(data);
}
scan.close();This pattern processes every item in the file without knowing the file size in advance.
Example: Sum Numbers from File
File numbers.txt:
Code:
import java.io.*;
import java.util.Scanner;
public class FileSum
{
public static void main(String[] args) throws IOException
{
File f = new File("numbers.txt");
Scanner scan = new Scanner(f);
int sum = 0;
while (scan.hasNext())
{
int num = scan.nextInt();
sum += num;
}
scan.close();
System.out.println("Sum: " + sum); // Sum: 150
}
}String split Method
The following additional String method is useful for processing file data:
String[] split(String del) — returns a String array where each element is a substring of this String, which has been split around matches of the given delimiter del.
Example with comma-separated values:
String line = "Alice,85,92,78";
String[] parts = line.split(",");
// parts[0] is "Alice"
// parts[1] is "85"
// parts[2] is "92"
// parts[3] is "78"Processing CSV Files
File scores.csv:
Code:
File f = new File("scores.csv");
Scanner scan = new Scanner(f);
while (scan.hasNext())
{
String line = scan.nextLine();
String[] parts = line.split(",");
String name = parts[0];
int test1 = Integer.parseInt(parts[1]);
int test2 = Integer.parseInt(parts[2]);
double avg = (test1 + test2) / 2.0;
System.out.println(name + ": " + avg);
}
scan.close();Complete Example
File students.txt:
Find average score:
import java.io.*;
import java.util.Scanner;
public class StudentAnalysis
{
public static void main(String[] args) throws IOException
{
File f = new File("students.txt");
Scanner scan = new Scanner(f);
int count = scan.nextInt();
int sum = 0;
for (int i = 0; i < count; i++)
{
String name = scan.next();
int score = scan.nextInt();
sum += score;
}
scan.close();
double average = (double) sum / count;
System.out.println("Average: " + average); // Average: 85.0
}
}Common Mistakes
Mistake 1: Forgetting throws IOException
// WRONG - won't compile
public static void readFile()
{
File f = new File("data.txt");
Scanner scan = new Scanner(f);
}Mistake 2: Forgetting to close the scanner
// WRONG - file resources not released
Scanner scan = new Scanner(new File("data.txt"));
// ... read data ...
// Missing: scan.close();Mistake 3: Not checking hasNext() before reading
// WRONG - may read past end of file
Scanner scan = new Scanner(new File("data.txt"));
int a = scan.nextInt();
int b = scan.nextInt(); // What if file only has one int?