File as path, not content
The java.io.File class is one of the most misnamed classes in the JDK. A File object does not hold the contents of a file: it holds the file's path, the string that names where a file might be on disk. new File("hamlet.txt") performs zero disk I/O; it just stores the string "hamlet.txt" inside a Java object. The disk is touched only when something else (a Scanner, a PrintStream, a method like exists()) asks the operating system about that path.
This separation is deliberate. A path can refer to a file that does not exist yet (you might be about to create it), a file you do not have permission to read, a directory rather than a file, or a perfectly normal readable file. The File class lets you build the reference, query the disk to find out which case you are in, and pass the reference to other classes that will actually open it.
import java.io.*;
final File f = new File("hamlet.txt"); // No disk I/O. Just a path object.
System.out.println(f.exists()); // Now we ask the OS: true or false?
System.out.println(f.getAbsolutePath()); // String formatting only: still no read.
In other languages
- Python:
pathlib.Path("hamlet.txt") is the direct analog: a path object you can query before opening. - C: there is no path object; you pass a
const char * filename directly to fopen. stat() and access() do what File.exists()/File.canRead() do.
Constructing a Scanner from a File
A Scanner is a tokenizer plus parser: it consumes a stream of characters and hands back chunks (next()), lines (nextLine()), or typed values (nextInt(), nextDouble()). To read from disk instead of the keyboard, swap the source: pass a File to the Scanner constructor.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public static int countLines(final String filename) throws FileNotFoundException {
final File f = new File(filename); // step 1: build the path object
final Scanner sc = new Scanner(f); // step 2: open the file for reading
int n = 0;
while (sc.hasNextLine()) {
sc.nextLine();
n++;
}
sc.close(); // step 3: release the file handle
return n;
}
Three things make this idiom different from the keyboard Scanner students wrote in earlier weeks:
1. The two-step construction. new File(filename) does not touch the disk; it only stores the path as an object. The disk read happens when the Scanner constructor actually opens the file. The two-step shape (new Scanner(new File(...))) is the convention because the File object also lets you call exists(), isFile(), canRead(), and other validation methods before opening.
2. You must close() what you open. Unlike the keyboard Scanner (which most programs intentionally leave open for the lifetime of the program), a file Scanner holds an OS file handle. Forgetting to close means the OS cannot reclaim it, and on some platforms it blocks other programs from accessing the file. Always close as soon as you have finished reading. (Week 7's "try-with-resources" introduces a syntax that closes for you, but the explicit close() is the foundation.)
3. The constructor is declared to throw FileNotFoundException. Every method that opens a file must either catch it or declare it on the header. The rule that FileNotFoundException is checked covers what that means.
What if I need two passes over the file?
Open a fresh Scanner each time. A Scanner does not have a rewind operation: once you have read past a line, you cannot go back without constructing a new Scanner on a new (or the same) File. The count-allocate-fill pattern, where pass 1 counts the values to learn how big an array to allocate and pass 2 fills the array, does exactly this: two Scanner objects, each closed after its pass.
In other languages
- Python:
open(filename, "r") returns a file object; iterating with for line in f: is the analog of while (sc.hasNextLine()). - C:
FILE *fp = fopen(filename, "r") followed by fgets or fscanf. fclose is the close() equivalent. - JavaScript (Node):
fs.readFileSync returns the whole content as a string; you then split or scan it yourself. There is no built-in lazy tokenizer like Scanner.