Lesson 14 - Working with files and folders in Java
In the previous lesson, Exceptions in Java for the third time and more techniques, we finished exceptions. Today we're going
to describe Java classes that don't depend on the file type in any way, so they
are for general use. They allow us to work with files and folders at the
operating system level, which we'll certainly need in our applications. In this
lesson we'll introduce the File
class, its methods and uses.
Absolute vs. relative path
Before we describe the File
class, let's talk briefly about the
absolute and relative path. Just to make these terms clear.
Absolute path
This is a path that starts with the root element of the filesystem. In the
case of Windows it'll be something like: C:\\
or D:\\
,
for Linux it'll be just /
. The absolute path does not need any
additional information to specify the location of the file. Everything is in one
place. But the problem is that the path is platform dependent. As we've already
mentioned, it differs for Windows and Linux. Therefore, I recommend not to use
absolute paths. Or just for program settings files.
Relative path
The relative path does not start with the root of the filesystem. Instead,
it's determined based on an existing location (most often the current program's
folder), such as images/
. This is definitely the way to go when
working with files in the program.
The File class
The File
class has been in Java since the first release. Over
time, it turned out that it had some "issues" which resulted in releasing a new
API (but we'll talk about this in the next lesson).
The class represents either a file or folder. We need to create a new instance to work with the file/folder. This can be done very simply:
File file = new File("file.txt");
The constructor has 4 overloads:
public File(String pathname); public File(String parent, String child); public File(File parent, String child) public File(URI uri)
In the first case, both absolute and relative paths can be passed. If we use a relative path, the result is always determined from the file used.
The file used is the resulting JAR file, not *.class.
The second overload receives two strings. The first string represents the path to the parent and can be either relative or absolute. The second parameter is the path relative to the parent in the first parameter. A parent is any parent folder, such as "C://". A child is a file/folder that is located in the parent folder, for example: "C://file.txt"
The third overload is the same as the first, but it differs in the first
parameter, which is now another instance of the File
class.
The last overload accepts an URI. It stands for Uniform Resource Identifier. (Do not confuse with URL). The complete URI syntax is shown below:
URI is a document identification standard using the scheme described below. URL is a "subset" of URI and contains information on how to handle resources from a location.
scheme:[//[user:password@]host[:port]][/]path[?query][#fragment]
This is the general scheme. But all we need is a basic one, where we replace 'scheme' with 'file' and then provide the path:
file:/tmp/soubor.txt
We'll most often encounter this approach when using various
images, sounds and other files that we pack in the JAR. We usually access these
files using the getClass().getResource(String name)
method. This
method returns the URI we pass to the File
constructor.
But we'll work with the first overload of the constructor most of the time.
The File class methods
The methods can be categorized into several categories:
- get
- set
- can
- is
- functional
GET methods
We have the following get methods available, which we'll all try:
getAbsolutePath(): String
- Returns the absolute path to the filegetCanonicalPath(): String
- Returns the canonized file pathgetFreeSpace(): long
- Returns the number of free bytes in the partition where the file is locatedgetName(): String
- returns the file namegetParent(): String
- returns the absolute path to the parent, ornull
if the file itself is the parentgetParentFile(): File
- Returns an instance of theFile
class representing the parent of the current filegetPath(): String
- returns the path to the file (since we don't know in which format we get it, it's better to usegetCanonicalPath()
instead)getTotalSpace(): long
- returns the total number of bytes in the partition where the file is locatedgetUsableSpace(): long
- Returns the number of used bytes for the current virtual machine; the result is more accurate than from thegetFreeSpace()
method
We'll make a few examples just to be sure. We'll create one instance of the
File
class and call all the GET methods on it.
For demonstration, I intentionally created an awkward directory structure to see the differences between the methods. Let's create the following folders:
src |---social | |---ict | |---filesfolders | |---App.java |---folders | |---file.txt
We'll create a File
class instance like this:
File file = new File("../../../files/file.txt");
We purposely used the ../
sequence several times
which takes us one folder up relatively to the current folder. This will make
the result more interesting.
Let's see the output of the individual methods:
Console application
getAbsolutePath(): /tmp/ict/files-folders/../../../files/file.txt
getCanonicalPath(): /files/file.txt
getFreeSpace(): 0
getName(): file.txt
getParent(): ../../../files
getParentFile(): ../../../files
getPath(): ../../../files/file.txt
getTotalSpace(): 0
getUsableSpace(): 0
SET methods
Set methods, as the name suggests, set some properties to the files. These are:
setExecutable(boolean executable, boolean ownerOnly): boolean
- sets whether the file is executable; the second parameter is optional (there's an overload where this parameter is set totrue
automatically); if the second parameter istrue
, then the executability is set for the current user onlysetLastModified(long time): boolean
- sets the date when the file has been lastly modifiedsetReadable(boolean readable, boolean ownerOnly): boolean
- sets whether the file can be read; the second parameter works the same as with the first methodsetReadOnly(): boolean
- a one-way method to set a file as read-only -> it won't be possible to write it anymoresetWritable(boolean writable, boolean ownerOnly): boolean
- sets whether it's possible to write to the file; the second parameter works the same as with the first method
CAN methods
The Can methods are the following:
canExecute(): boolean
- Returnstrue
if the file can be executed,false
otherwisecanRead(): boolean
- returntrue
if the file is readable,false
otherwisecanWrite(): boolean
returnstrue
if writable,false
otherwise
IS methods
Using the "IS" methods we can ask the following questions:
isAbsolute(): boolean
- Returnstrue
if the instance was created using an absolute pathisDirectory(): boolean
- Returnstrue
if it's a folderisFile(): boolean
- Returnstrue
if it's a fileisHidden(): boolean
- Returnstrue
if the file is hidden
FUNCTIONAL methods
We're now missing only the "functional" that do something with the file itself and which we'll use most often.
toURI(): URI
- Creates a URI from the file instance usedcreateNewFile(): boolean
- creates a new file if it doesn't exist; returnstrue
if the file was created,false
otherwisedelete(): boolean
- deletes the file; returnstrue
if the file was deleted,false
otherwisedeleteOnExit(): void
- deletes the file only after the program has finishedexists(): boolean
- returnstrue
if the file exists,false
otherwiselength(): long
- returns the file size in byteslist(): String []
- returns an array of absolute paths of the files in the folderlistFiles(): File []
- Returns an array of file instances in the foldermkdir(): boolean
- attempts to create the folder; returnstrue
if the folder was created,false
otherwisemkdirs(): boolean
- attempts to create all folders in the path; returnstrue
if all the folders have been created,false
otherwiserenameTo(File dest): boolean
- renames the file to a new name; can be understood as "moving" a file from one location to another; this method is platform dependent; cannot be used to move the file between two file systemstoPath(): Path
- creates a newPath
instance, which we'll discuss in the next lesson
The File API problems
The File
API suffers from the following problems:
- the vast majority of methods return only
true
orfalse
if something goes wrong; the problem is that we don't know the cause of the failure - renaming a file does not work the same on all platforms
- The API does not support symbolic links
- The API is missing metadata support (permissions, file owner, ...)
In the next lesson, Working with files and folders in Java - New API, we'll introduce new classes for working with files and folders that solve these problems.