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:[email protected]]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 file
  • getCanonicalPath(): String - Returns the canonized file path
  • getFreeSpace(): long - Returns the number of free bytes in the partition where the file is located
  • getName(): String - returns the file name
  • getParent(): String - returns the absolute path to the parent, or null if the file itself is the parent
  • getParentFile(): File - Returns an instance of the File class representing the parent of the current file
  • getPath(): String - returns the path to the file (since we don't know in which format we get it, it's better to use getCanonicalPath() instead)
  • getTotalSpace(): long - returns the total number of bytes in the partition where the file is located
  • getUsableSpace(): long - Returns the number of used bytes for the current virtual machine; the result is more accurate than from the getFreeSpace() 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 to true automatically); if the second parameter is true, then the executability is set for the current user only
  • setLastModified(long time): boolean - sets the date when the file has been lastly modified
  • setReadable(boolean readable, boolean ownerOnly): boolean - sets whether the file can be read; the second parameter works the same as with the first method
  • setReadOnly(): boolean - a one-way method to set a file as read-only -> it won't be possible to write it anymore
  • setWritable(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 - Returns true if the file can be executed, false otherwise
  • canRead(): boolean - return true if the file is readable, false otherwise
  • canWrite(): boolean returns true if writable, false otherwise

IS methods

Using the "IS" methods we can ask the following questions:

  • isAbsolute(): boolean - Returns true if the instance was created using an absolute path
  • isDirectory(): boolean - Returns true if it's a folder
  • isFile(): boolean - Returns true if it's a file
  • isHidden(): boolean - Returns true 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 used
  • createNewFile(): boolean - creates a new file if it doesn't exist; returns true if the file was created, false otherwise
  • delete(): boolean - deletes the file; returns true if the file was deleted, false otherwise
  • deleteOnExit(): void - deletes the file only after the program has finished
  • exists(): boolean - returns true if the file exists, false otherwise
  • length(): long - returns the file size in bytes
  • list(): String [] - returns an array of absolute paths of the files in the folder
  • listFiles(): File [] - Returns an array of file instances in the folder
  • mkdir(): boolean - attempts to create the folder; returns true if the folder was created, false otherwise
  • mkdirs(): boolean - attempts to create all folders in the path; returns true if all the folders have been created, false otherwise
  • renameTo(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 systems
  • toPath(): Path - creates a new Path 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 or false 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.


 

 

Activities (2)

 

 

Comments

To maintain the quality of discussion, we only allow registered members to comment. Sign in. If you're new, Sign up, it's free.

No one has commented yet - be the first!