Using the File Class
A Java File object represents a file or directory, and creating one with new File(name) asks the program to refer to a path rather than read it.
Predicting the Result for an Ordinary File
This article follows one complete Java program, DirectoryList. The program asks the user to type in a directory name and then lists the files inside it. If the name entered is not a directory, the program prints a message and ends. The goal is to learn how the program decides what to do, not only what it prints. As you read, keep the program's purpose in mind and watch which checks run for each input.
What do you think happens?
Suppose the user types the name of an ordinary file, not a folder. Which result does the program produce?
Reveal answer
The file is not a directory
The file exists, so the program does not print the no-such-directory message. Because isDirectory() returns false, the outer if block runs, and the nested check finds that the path exists but is not a directory. The program never calls list() on it.
A File Object Holds a Name
A java.io.File object represents a file or directory by holding a path name. The named file may or may not exist, and creating the object creates nothing on disk.
The word File in the class name invites a wrong reading: that creating a File object opens or creates a file. The source tests that assumption directly. The line that creates the object does not read anything from the disk by itself. It builds an object that refers to the path the user typed, and the program then asks that object questions.
- The constructor only stores the path string
notes.txtinside the object exists()asks the file system whether that name is present
Creating a File object is a request to refer to a path. Asking exists() or isDirectory() is what checks the disk. Until you ask, the object tells you nothing about contents.
Two Ways to Build a File Object
Two constructors build File objects. new File(String) takes a single path string. new File(File, String) takes a directory and a name or relative path, and combines the two parts into one path. Which one you choose depends on how much of the path you already have as separate pieces. Both produce the same kind of object, so the later checks apply to either.
- single is built from one complete path string
- combined is built from a directory object and a relative name, and the constructor joins them
| Constructor | Inputs | Best used when |
|---|---|---|
| new File(String) | One path string | The whole path arrives as a single piece of text, such as typed user input |
| new File(File, String) | A File for the directory and a name or relative path | The directory and the entry name are already separate pieces |
The two File constructors and when each fits
Tracing the Validity Check
The program first tests directory.isDirectory() == false. This is a negated test: the outer if block runs when the path is not a directory. Inside that block, the program separates two cases. If directory.exists() == false, nothing by that name is present, so the message is that there is no such directory. Otherwise, something exists but it is not a directory, so the message is that the file is not a directory. Only when isDirectory() is true does the else branch run, and only then does the program call list(). The nested if is what separates a missing path from an existing file, so a non-directory input always gets a specific message.
Read the diagram from the top. The first decision is always isDirectory(). A missing path and an ordinary file both take the left-hand branch, and only the second decision separates them. Only the path on the right, where isDirectory() is true, reaches list(). Everything that prints a file name comes after the validity check has passed.
Walking Three Inputs Through the Branches
Tracing an ordinary file name
The user types notes.txt, where notes.txt is an ordinary file in the current folder. Which branch runs and what does the program print?
- 1Create the object
new
File("notes.txt")stores the path. Nothing is read from the disk yet. - 2Test isDirectory()
The method returns false, because the entry is a regular file. The negated test
directory.isDirectory()== false is therefore true, and the outer if block runs. - 3Test exists()
The method returns true, because the file is present. The check
directory.exists()== false is therefore false, so the program takes the otherwise path. - 4Print the message
Since the entry exists but is not a directory, the program prints that the file is not a directory and ends.
list()is never called.
The program prints that the file is not a directory. No file listing appears.
Now change the input to a name that is not present anywhere. The first test is still isDirectory(), which returns false. The second test, exists(), now returns false, so the program prints that there is no such directory. The two non-directory inputs differ only in the nested check, which is why the program can give a specific message for each. A valid directory is the only input that skips both messages and reaches the listing.
Why list() Runs Last
The list() method returns an array of file names in the directory. The program stores that array in the variable files, uses files.length as the loop limit, and prints each entry on an indented line. The ordering matters. Because list() is called only after isDirectory() has returned true, the program never asks a regular file for its contents. The message branches and the listing branch are therefore separate, safe paths.
- The
isDirectory()check guards the call tolist() list()returns names, which are plain stringsfiles.lengthbounds the loop, so each name is printed once
Object Versus File on Disk
The clearest way to hold the two ideas apart is to set them side by side. The File object lives in your program and carries a name. The file lives in the file system and carries contents. The name and the file are linked only when the operating system finds a match for that name. The diagram shows that link as a question you ask across the arrow, not as something the object already knows.
Asking Questions About an Entry
Because a File object holds a name, its useful operations are questions and requests about that name. Does the named entry exist? Can the program read or write it? Is it a directory? Should it be deleted? If it is a directory, what does it contain? The table groups the main instance methods by the question each one answers.
| Method | Question it answers about the path |
|---|---|
| exists() | Is anything present at this path? |
| canRead() | Can the program read this entry? |
| canWrite() | Can the program write to this entry? |
| isDirectory() | Does the path refer to a directory? |
| delete() | Remove the named entry |
| list() | Return the names inside a directory, as an array of strings |
| listFiles() | Return the contents of a directory as File objects |
Main File methods grouped by the question each answers
list() and listFiles() return directory contents only when the object refers to a directory. Calling them on a regular file is the mistake the DirectoryList program avoids by checking isDirectory() first.
Checking State Before Handing a File to FileReader
Stream classes such as FileReader accept a File object in their constructors, which is how a named file becomes a source of data. The usual order is to create the File, ask questions about its state, and only then pass it to the stream. The source also notes that exists() helps you avoid overwriting an existing file when you create a new output stream, so the same check serves both reading and writing.
- Step 1 creates the File object, which only holds the name
- Step 2 asks
exists()andcanRead()about that name - Step 3 hands the File to
FileReaderonly when the checks pass
Mistakes Beginners Make with File Objects
Common mistake Assuming new File(name) creates the file on disk
What it looks likeFile f = new File("notes.txt"); then expecting notes.txt to now be present
Why it failsA File object holds a name. Creating it creates nothing on disk, and the named file may or may not exist.
Do this insteadUse exists() to ask whether the file is present before you rely on it.
Common mistake Calling list() before checking isDirectory()
What it looks likeCalling list() on the path an ordinary file name refers to
Why it failslist()returns directory contents only when the object refers to a directory, so the call is not meaningful for a regular file.Do this insteadPlace list() inside the branch that runs only after isDirectory() returns true.
Common mistake Treating an ordinary file and a missing path as the same case
What it looks likePrinting one generic error for every non-directory input
Why it failsA missing path and an existing non-directory need different messages, and only a nested
exists()check separates them.Do this insteadKeep the nested exists() test inside the negated isDirectory() branch.
Common mistake Forgetting that isDirectory() is a question about the path, so its answer depends on what is on disk when you ask
Practice: Predict the Branch
A user types the name of a folder that exists. Without running the program, trace the branches. Which checks run, which branch is taken, and what does the program print? Then explain why the program never calls list() on a missing path.
Hints
- Start with
directory.isDirectory()== false. What does it return for a folder? - If the negated test is false, which block is skipped entirely?
list()sits only in the else branch, so ask what condition has to be true to reach it.
Key Takeaways
- A File object holds a path name, not file contents, and creating it does nothing on disk until you ask questions such as
exists()orisDirectory(). - In
DirectoryList,isDirectory()is checked first, and a nestedexists()test separates a missing path from an existing non-directory, so each invalid input gets a specific message. list()returns the names inside a directory and is only called after the validity check passes, which keeps the listing branch safe.- The constructors new
File(String)and newFile(File, String)build the same kind of object, so the checks described here apply to either one. - Check a file's state with
exists()andcanRead()orcanWrite()before passing the File object to a stream such asFileReader.