Accessing Resources using Paths
Introducing the Legacy File Class
There two ways to model a file or a path on a file system in Java. The first, legacy one, is the File class. This class is mentioned here, with a word of warning: you should not use it anymore in your code, unless you have very good reasons to do so. You should favor the use of the Path interface, also covered in this section. Along with the factory methods from the Files, it gives you more features than the File class, and better performances, especially to access larger files and directories.
That been said, because it is widely used in legacy code, understanding the File may still be important to you. Without diving too deep in it, let us present the main concepts of this class.
An instance of the File class can represent anything on a file system: a file, a directory, a symbolic link, a relative path, or an absolute path. This instance is an abstract notion. Creating such an instance does not create anything on your file system. You can query your file system using this class, but you need to do it explicitly.
An instance of a File does not allow you to access the content of the file it represents. With this instance, you can check if this file exists or is readable (among other things).
A file is composed of several elements, separated by a separator, which depends on your file system. The first element may be a prefix, such as a disk-drive specifier, a slash for the UNIX root directory. The other elements are names.
Creating an Instance of File
You can create an instance of the File class using several constructors:
File(String pathName): creates a file from the path you provide.File(String parent, String child): create the given file in theparentdirectory.File(File parent, String child): create the given file in theparentdirectory, specified as an instance ofFile.File(URI uri): create a file from aURI.
Getting the Elements of a File
The following methods give you information on the elements of this file:
getName(): returns the name of the file or directory denoted by this file object. This is just the last name of the sequence.getParent(): returns the pathname string of this abstract pathname's parent, or null if this pathname does not name a parent directory.getPath(): returns this abstract pathname converted into a pathname string. This method is not related to thePathinterface.getAbsolutePath(): returns the absolute pathname string of this abstract pathname. If this abstract pathname is already absolute, then the pathname string is simply returned. Otherwise this pathname is resolved in a system-dependent way.getCanonicalPath(): returns the canonical pathname string of this abstract pathname. The canonical pathname is absolute and unique and system-dependent. The construction of this canonical pathname typically involves removing redundant names such as.and..from the pathname, and resolving symbolic links.
Getting Information on a File or a Directory
Some of these methods may require special rights on files or directories. As a legacy class, the File does not expose all the security attributes offered by your file system.
isFile(),isDirectory(): checks if this abstract pathname denotes an existing file or directory.exists(),canRead(),canWrite(),canExecute(): checks if this file exists, is readable, if you can modify it, or if you can execute it.setReadable(boolean),setWritable(boolean),setExecutable(boolean): allows you to change the corresponding security attribute of the file. These methods returntrueif the operation succeeded.lastModified()etsetLastModified(): return or set the time that this file was last modified.length(): returns the length of the file denoted by this abstract pathname.isHidden(): tests whether the file named by this abstract pathname is a hidden file.
Manipulating Files and Directories
Several methods allow you to create files and directories on a file system. Most of them are file system dependent. Remember that these methods are legacy methods. You can check the section Refactoring your Code to Using Path to refactor your code to use the equivalent methods from the Path interface and the Files class.
createNewFile(): tries to create a new file from this pathname. This creation will fail if this file already exists. This method returnstrueif the file was successfully created, andfalseotherwise.delete(): deletes the file or directory denoted by this abstract pathname. If this pathname denotes a directory, then the directory must be empty in order to be deleted. This method returnstrueif the file was successfully deleted andfalseotherwise. You should favor the use of theFiles.delete()method over this one, since it gives you more information in case the deletion fails.mkdirs()andmkdir(): create a directory named by this abstract pathname.mkdirs()creates all the intermediate directories if needed.renameTo(file): renames the file denoted by this abstract pathname.
Introducing the Path Interface
The Path class, introduced in the Java SE 7 release, is one of the primary entrypoint of the java.nio.file package. If your application uses file I/O, you will want to learn about the powerful features of this interface.
Version Note: If you have pre-JDK7 code that uses
java.io.File, you can still take advantage of thePathinterface functionality by using theFile.toPath()method. See the next section for more information. As its name implies, thePathinterface is a programmatic representation of a path in the file system. APathobject contains the file name and directory list used to construct the path, and is used to examine, locate, and manipulate files.
A Path instance reflects the underlying platform. In the Solaris OS, a Path uses the Solaris syntax (/home/joe/foo) and in Microsoft Windows, a Path uses the Windows syntax (C:\home\joe\foo). A Path is not system independent. You cannot compare a Path from a Solaris file system and expect it to match a Path from a Windows file system, even if the directory structure is identical and both instances locate the same relative file.
The file or directory corresponding to the Path might not exist. You can create a Path instance and manipulate it in various ways: you can append to it, extract pieces of it, compare it to another path. At the appropriate time, you can use the methods in the Files class to check the existence of the file corresponding to the Path, create the file, open it, delete it, change its permissions, and so on.
Refactoring your Code to Using Path
Perhaps you have legacy code that uses java.io.File and would like to take advantage of the java.nio.file.Path functionality with minimal impact to your code.
The java.io.File class provides the toPath() method, which converts an old style java.io.File instance to a java.nio.file.Path instance, as follows:
Path input = file.toPath();
You can then take advantage of the rich feature set available to the Path interface.
For example, assume you had some code that deleted a file:
file.delete();
You could modify this code to use the Files.delete() factory method, as follows:
Path fp = file.toPath();
Files.delete(fp);
Conversely, the Path.toFile() method constructs a java.io.File object for a Path object.
Because the Java implementation of file I/O has been completely re-architected in the Java SE 7 release, you cannot swap one method for another method. If you want to use the rich functionality offered by the java.nio.file package, your easiest solution is to use the File.toPath() method. However, if you do not want to use that approach or it is not sufficient for your needs, you must rewrite your file I/O code.
There is no one-to-one correspondence between the two APIs, but the following table gives you a general idea of what functionality in the java.io.File API maps to in the java.nio.file API and tells you where you can obtain more information.
Last update: January 25, 2023