Concepts / Handling Exceptions in File Operations

Handling Exceptions in File Operations

A File object represents a file name, not a file. The named file may or may not exist, and creating the object creates nothing on disk.

  • Programming

Predicting What a File Object Does

When beginners first meet the java.io.File class, many assume that creating a File object is the same as opening or creating a file on disk. The word File in the class name encourages this reading. This article tests that assumption directly, because the assumption is wrong in a way that shapes every later step of file handling in Java.

What do you think happens?

Suppose a program creates a File object for the name notes.txt in a folder that contains no such file. What does exists() return for that object?

  • true, because the File object creates notes.txt

  • false, because the File object holds only a name and creates nothing on disk

  • It throws an exception the moment the File object is created

Reveal answer
Answer:

false, because the File object holds only a name and creates nothing on disk

A File object represents a file name, not a file. The named file may or may not exist, and creating the object creates nothing on disk. Since no notes.txt exists in that folder, exists() reports that it does not. Keep this answer in mind, because the rest of the article explains why it is correct.

Keep the wrong belief in mind as you read. Each section below either confirms or corrects a part of it, and by the end you should be able to explain what a File object actually holds and what it can tell you.

What a File Object Holds

Definition

A File object represents a file name, not a file. The named file may or may not exist, and creating the object creates nothing 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.

File objectlives in the programnotes.txtthe name it holdsnotes.txt on diskmay or may not existholdsmatched only if the OS finds it
How is the File object in memory related to the actual file on disk, and what changes (or doesn't) when the File object is created?

Read the diagram as a warning as much as an explanation. Creating the File object only creates the box on the left. Nothing on the right changes. Whether the arrow reaches a real file is a question you must ask, and the methods in the following sections are how you ask it.

Building a File Object

A File object is built with one of two constructors. 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 everything in the later sections applies to either.

Building a Filenew File(String)one path stringdata/notes.txtwhole path given at oncenew File(File,String)directory plus namedata + notes.txtpieces joined into a pathwhen you havewhen you havebuildsbuilds
How does a path string combine a parent directory and a file name, and how do the two constructors produce the same or different File paths?

Asking Questions About a Named Entry

Because a File object holds a name, the 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, and what does it contain if it is a directory. The table below groups the main instance methods by the question each one answers.

QuestionMethodWhat it reports or does
Does the named entry exist?exists()Whether something with this name is present
Can the program read it?canRead()Whether reading the named entry is permitted
Can the program write to it?canWrite()Whether writing to the named entry is permitted
Is it a directory?isDirectory()Whether the named entry is a directory
Should it be removed?delete()Requests removal of the named entry
What does a directory contain, as names?list()Returns the entry names inside a directory
What does a directory contain, as File objects?listFiles()Returns the entries inside a directory as File objects

Main instance methods of java.io.File, grouped by the question each answers

The methods that ask about contents, list() and listFiles(), return contents only when the object refers to a directory. Asking a regular file for its entries answers nothing useful, so check isDirectory() first when you do not know what kind of entry you hold.

java
Output
false
false
false
Notes on the code
  • Each method asks a question about the same named entry
  • If data/notes.txt is absent, every answer is false, because nothing is there to read or be a directory

Tracing a File Through delete()

Worked example

Checking existence before and after delete()

Assume data/notes.txt exists on disk when the program starts. What does exists() report before and after delete() is called?

  1. 1
    Create the object

    new File("data/notes.txt") holds the name. It does not touch the disk.

  2. 2
    Ask before deleting

    exists() looks for the named entry. The file is present, so it returns true.

  3. 3
    Request deletion

    delete() acts on the named entry. The file is removed from the file system.

  4. 4
    Ask again

    exists() now looks for the same name and finds nothing, so it returns false. The File object itself is unchanged; only the disk changed.

Result

exists() returns true before delete() and false afterward. The File object holds the same name in both cases.

java
Output
true
false
Notes on the code
  • The first exists() call sees the file because it was present before the program started
  • The second call sees no file, so the answer changes without the File object changing

Listing a Directory's Entries

When the File object refers to a directory, list() and listFiles() give you its contents. The difference is the form of each entry. list() returns the entries as names, which you can use as text. listFiles() returns each entry as a File object, which you can then ask questions of with the methods above.

java
Output
notes.txt
report.txt
Notes on the code
  • isDirectory() guards the call so the listing only runs on a directory
  • Each element is a File, so getName() can be called on it
  • The output shown assumes data/ holds notes.txt and report.txt

Checking State Before Writing

The source explains that exists() helps you avoid overwriting an existing file when you create a new output stream. Before you write, you ask the object what it finds at that name, and only then decide whether to proceed. The flowchart shows that decision in its simplest form.

Build File objectexists()?Choose another nameavoid overwritingOpen output streamno existing file tooverwritecheckyesno
In what order should the checks run, and which outcome leads to writing, reading, or stopping?
java
Output
Safe to create notes.txt
Notes on the code
  • The check runs before any output stream is created
  • The output shown assumes data/notes.txt is absent

Passing a File to FileReader

Stream classes such as FileReader accept a File object in their constructors. This is how a named file becomes a source or destination of data. The File object supplies the name, and the stream uses that name to reach the contents on disk. The File object does not carry the data; the stream does the reading.

java
Notes on the code
  • The state checks come before the stream is created
  • The File object is passed straight into the FileReader constructor
  • Closing the reader is omitted here to keep the focus on the File

Mistakes Beginners Make with File Objects

  • Common mistake

    Assuming new File(...) creates the file on disk

    What it looks like

    File f = new File("data/notes.txt"); then expecting notes.txt to appear in the folder

    Why it fails

    A File object represents a file name, and creating the object creates nothing on disk

    Do this instead

    Create the file explicitly through an output stream, after checking exists()

  • Common mistake

    Calling list() or listFiles() on a regular file

    Why it fails

    Directory contents are returned only when the object refers to a directory

    Do this instead

    Check isDirectory() before asking for entries

  • Common mistake

    Opening an output stream without checking exists() first

    Why it fails

    Without the check, an existing file can be overwritten

    Do this instead

    Ask exists() before creating the output stream and decide what to do if the answer is true

  • Common mistake

    Expecting the File object to change when the file is deleted

    What it looks like

    After delete(), printing the same File object's name still shows notes.txt

    Why it fails

    The object holds the name, and the name is unchanged; only the disk state changed

    Do this instead

    Ask exists() again to learn the new state of the file

Practice Checking a File's State

MEDIUM

A program holds a File object for the name report.txt inside a folder called logs. Write the steps that check whether report.txt exists, whether it can be read, and whether it is a directory, in that order. Then say which answer would stop the program from opening a FileReader.

Hints
  • Build the object with either constructor and check exists() before anything else
  • A missing file means canRead() cannot be true for that name
  • A directory is not a file a FileReader can read as text, so isDirectory() being true is a reason to stop

Key Takeaways

  • A File object represents a file name, not a file, and creating it creates nothing on disk
  • Two constructors build File objects: new File(String) from a path string, and new File(File, String) from a directory and a name
  • exists(), canRead(), canWrite(), isDirectory(), and delete() ask questions about the named entry, and list() and listFiles() return contents only for a directory
  • Check a file's state with exists() before creating an output stream, so an existing file is not overwritten by accident
  • Passing a File object to FileReader connects a named file to a stream, but the stream does not check the state for you