Index

File and Directory Operations

Java IO and NIO

3.1 Working with Files: File Class Overview

In Java, the java.io.File class serves as an abstract representation of file and directory pathnames in the filesystem. Unlike stream classes that handle reading and writing data, the File class focuses on metadata and structure—such as verifying whether a file or directory exists, checking permissions, and creating or deleting files and directories.

The File class is part of the java.io package and plays a critical role in Java IO operations involving filesystems.

What is the File Class?

The File class encapsulates the pathname of a file or directory (absolute or relative). However, a File object does not represent actual file content—it represents a path string and provides methods to interact with the file or directory associated with that path.

Creating a File Object

File file1 = new File("example.txt");             // Relative path
File file2 = new File("/home/user/example.txt");  // Absolute path

This does not create a new file; it only creates a File object pointing to a path.

Querying File and Directory Properties

The File class provides several methods to inspect file properties:

Checking Existence

File file = new File("example.txt");
System.out.println("Exists: " + file.exists());

Checking Type

System.out.println("Is file: " + file.isFile());
System.out.println("Is directory: " + file.isDirectory());

Getting Size and Path

System.out.println("Absolute path: " + file.getAbsolutePath());
System.out.println("File name: " + file.getName());
System.out.println("Parent directory: " + file.getParent());
System.out.println("File size (bytes): " + file.length());

Checking Permissions

System.out.println("Readable: " + file.canRead());
System.out.println("Writable: " + file.canWrite());
System.out.println("Executable: " + file.canExecute());

These checks are particularly useful for verifying access before performing IO operations.

Creating Files and Directories

Creating a New File

File file = new File("newfile.txt");
try {
    if (file.createNewFile()) {
        System.out.println("File created.");
    } else {
        System.out.println("File already exists.");
    }
} catch (IOException e) {
    e.printStackTrace();
}

Creating Directories

File dir = new File("myDirectory");
if (dir.mkdir()) {
    System.out.println("Directory created.");
}

File nestedDir = new File("parent/child/grandchild");
if (nestedDir.mkdirs()) {
    System.out.println("Nested directories created.");
}

Deleting Files and Directories

Deleting a File or Directory

File file = new File("toDelete.txt");
if (file.delete()) {
    System.out.println("Deleted successfully.");
} else {
    System.out.println("Deletion failed.");
}

Renaming and Moving Files

Renaming a File

File oldFile = new File("old.txt");
File newFile = new File("new.txt");

if (oldFile.renameTo(newFile)) {
    System.out.println("File renamed successfully.");
} else {
    System.out.println("Rename failed.");
}

Listing Directory Contents

You can list files and directories inside a folder using list() or listFiles().

Listing File Names

File directory = new File("myDirectory");
String[] fileList = directory.list();

for (String name : fileList) {
    System.out.println(name);
}

Listing as File Objects

File[] files = directory.listFiles();
for (File f : files) {
    System.out.println(f.getName() + (f.isDirectory() ? " (dir)" : " (file)"));
}

These methods are helpful for building file browsers, searching files, or batch processing.

Working with Paths

Absolute vs Relative Paths

File relative = new File("data.txt");
System.out.println("Absolute path: " + relative.getAbsolutePath());

File absolute = new File("/usr/local/data.txt");
System.out.println("Is absolute: " + absolute.isAbsolute());

Practical Use Case: File Validation

public static void validateFile(String path) {
    File file = new File(path);
    if (!file.exists()) {
        System.out.println("File not found.");
        return;
    }
    if (!file.isFile()) {
        System.out.println("Not a regular file.");
        return;
    }
    if (!file.canRead()) {
        System.out.println("Cannot read file.");
        return;
    }

    System.out.println("File is ready for processing: " + file.getName());
}

This kind of validation is essential before attempting to read from or write to a file.

Click to view full runnable Code

import java.io.File;
import java.io.IOException;

public class FileExample {
    public static void main(String[] args) {
        try {
            // Create a new file
            File file = new File("example.txt");
            if (file.createNewFile()) {
                System.out.println("File created: " + file.getName());
            } else {
                System.out.println("File already exists.");
            }

            // Check file properties
            System.out.println("Exists: " + file.exists());
            System.out.println("Is file: " + file.isFile());
            System.out.println("Is directory: " + file.isDirectory());
            System.out.println("Readable: " + file.canRead());
            System.out.println("Writable: " + file.canWrite());
            System.out.println("Executable: " + file.canExecute());
            System.out.println("Absolute path: " + file.getAbsolutePath());
            System.out.println("File size (bytes): " + file.length());

            // Create a directory
            File dir = new File("demoDir");
            if (dir.mkdir()) {
                System.out.println("Directory created: " + dir.getName());
            }

            // Rename file
            File renamed = new File("renamed_example.txt");
            if (file.renameTo(renamed)) {
                System.out.println("File renamed to: " + renamed.getName());
            }

            // List contents of current directory
            File current = new File(".");
            File[] files = current.listFiles();
            if (files != null) {
                System.out.println("\nDirectory contents:");
                for (File f : files) {
                    System.out.println(f.getName() + (f.isDirectory() ? " (dir)" : " (file)"));
                }
            }

            // Delete the renamed file
            if (renamed.delete()) {
                System.out.println("\nDeleted file: " + renamed.getName());
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Recap

The Java File class is a foundational component of the IO system, enabling applications to interact with the filesystem in a platform-independent way. While it doesn't handle file contents directly, it provides robust support for inspecting and manipulating files and directories. Mastery of File is essential for tasks like file validation, path resolution, directory traversal, and metadata querying. For file content operations, it is typically used in conjunction with stream or reader/writer classes.

Index

3.2 Reading and Writing Files with FileInputStream and FileOutputStream

In Java IO, the FileInputStream and FileOutputStream classes are fundamental for performing byte-oriented file input and output operations. These classes are part of the java.io package and are typically used when dealing with binary data such as images, audio files, PDFs, or raw byte sequences.

Understanding Byte Streams

Java’s IO system is built around two types of streams:

FileInputStream and FileOutputStream are concrete implementations of the byte stream classes specifically designed to work with files.

FileInputStream Reading Bytes from a File

FileInputStream allows you to read bytes from a file. It is ideal for reading binary files or when you need precise control over the byte-level structure of the data.

Key Methods

Example: Reading a File Byte-by-Byte

import java.io.FileInputStream;
import java.io.IOException;

public class FileReadExample {
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("input.bin")) {
            int byteData;
            while ((byteData = fis.read()) != -1) {
                System.out.print((char) byteData); // Cast to char for text output
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Explanation:

FileOutputStream Writing Bytes to a File

FileOutputStream lets you write bytes to a file. It's commonly used for creating or modifying binary files.

Key Methods

Example: Writing Bytes to a File

import java.io.FileOutputStream;
import java.io.IOException;

public class FileWriteExample {
    public static void main(String[] args) {
        String data = "Java FileOutputStream Example";

        try (FileOutputStream fos = new FileOutputStream("output.txt")) {
            byte[] bytes = data.getBytes(); // Convert string to byte array
            fos.write(bytes);              // Write all bytes to file
            System.out.println("Data written to file.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Explanation:

Writing in Append Mode

To append data to an existing file instead of overwriting it, use the FileOutputStream constructor with a true flag:

try (FileOutputStream fos = new FileOutputStream("log.txt", true)) {
    fos.write("New log entry\n".getBytes());
}

This mode is useful for logging or appending updates to a file.

Using Buffers for Efficiency

Reading or writing byte-by-byte is inefficient for large files. Use a byte array buffer to read/write chunks of data:

Buffered Reading and Writing

import java.io.*;

public class FileCopyExample {
    public static void main(String[] args) {
        try (
            FileInputStream fis = new FileInputStream("source.jpg");
            FileOutputStream fos = new FileOutputStream("copy.jpg")
        ) {
            byte[] buffer = new byte[4096]; // 4 KB buffer
            int bytesRead;

            while ((bytesRead = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, bytesRead); // Write only bytes read
            }

            System.out.println("File copied successfully.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Advantages:

Common Use Cases

For text files, FileReader and FileWriter (or their buffered counterparts) are preferred to handle character encoding.

Error Handling and Resource Management

Always close file streams to avoid resource leaks. The try-with-resources statement ensures this automatically:

try (FileInputStream fis = new FileInputStream("input.txt")) {
    // use the stream
} catch (IOException e) {
    e.printStackTrace();
}

Important Considerations

Conclusion

FileInputStream and FileOutputStream are powerful classes in Java’s IO toolkit, offering efficient and low-level control over reading and writing byte data to and from files. Whether you're building a file copier, manipulating binary files, or handling large datasets, these classes provide the foundation for reliable and performant IO operations. By combining them with buffering and proper resource management, you can ensure that your file-handling code is both fast and safe.

Index

3.3 Reading and Writing Files with FileReader/FileWriter

Java provides two broad categories of stream classes for file input and output:

FileReader and FileWriter are concrete implementations of the character stream classes. They are specifically used to read from and write to text files, automatically handling character encoding based on the system’s default or specified charset.

Why Use Character Streams?

When dealing with text files, character streams are preferred over byte streams for several reasons:

For binary data such as images or audio files, byte streams are better suited. But for textual data—such as .txt, .csv, .xml, .jsonFileReader and FileWriter are more convenient and semantically appropriate.

FileReader Reading Characters from a File

FileReader is a subclass of InputStreamReader, designed to read character data from a file using the default platform encoding (e.g., UTF-8 or ISO-8859-1, depending on the system).

Basic Usage

import java.io.FileReader;
import java.io.IOException;

public class FileReaderExample {
    public static void main(String[] args) {
        try (FileReader reader = new FileReader("example.txt")) {
            int character;
            while ((character = reader.read()) != -1) {
                System.out.print((char) character); // Cast int to char
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Explanation:

FileWriter Writing Characters to a File

FileWriter is a subclass of OutputStreamWriter and allows you to write character data directly to a file.

Basic Usage

import java.io.FileWriter;
import java.io.IOException;

public class FileWriterExample {
    public static void main(String[] args) {
        String content = "This text is written using FileWriter in Java.";

        try (FileWriter writer = new FileWriter("output.txt")) {
            writer.write(content);  // Writes the entire string
            System.out.println("Data written to file.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Explanation:

Writing in Append Mode

To append text to an existing file without overwriting:

try (FileWriter writer = new FileWriter("log.txt", true)) {
    writer.write("Appended text line.\n");
}

The second argument true tells FileWriter to append rather than overwrite.

Buffered Character Streams

Reading and writing character-by-character is inefficient. For better performance, wrap FileReader or FileWriter with buffered streams:

BufferedReader Example

import java.io.*;

public class BufferedReaderExample {
    public static void main(String[] args) {
        try (BufferedReader reader = new BufferedReader(new FileReader("notes.txt"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);  // Reads line by line
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

BufferedWriter Example

import java.io.*;

public class BufferedWriterExample {
    public static void main(String[] args) {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter("notes.txt"))) {
            writer.write("First line of text.");
            writer.newLine(); // Platform-specific line separator
            writer.write("Second line.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Using buffered streams is highly recommended for performance and convenience (e.g., readLine(), newLine()).

Handling Character Encoding

By default, FileReader and FileWriter use the platform's default encoding, which can vary. To explicitly control encoding (such as UTF-8), use InputStreamReader and OutputStreamWriter:

Specifying Encoding

import java.io.*;
import java.nio.charset.StandardCharsets;

public class UTF8WriterExample {
    public static void main(String[] args) {
        try (Writer writer = new OutputStreamWriter(new FileOutputStream("utf8.txt"), StandardCharsets.UTF_8)) {
            writer.write("Writing with UTF-8 encoding.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

This ensures consistent behavior across platforms, especially when dealing with non-ASCII characters.

Typical Use Cases for Character Streams

Recap

FileReader and FileWriter provide a simple, high-level way to handle text-based file input and output in Java. Unlike byte streams, they automatically handle character encoding and make it easier to work with strings, characters, and lines. For more efficient and robust applications, it’s often best to combine them with buffered streams and to explicitly set the character encoding when needed. These classes form the foundation of many file-based applications in Java that deal with human-readable data.

Index

3.4 File Permissions and Attributes

Managing file permissions and attributes is an essential part of file handling in Java. Whether you are developing applications that need to check if files are accessible, or modify permissions for security reasons, Java provides several ways to work with these properties — from the basic File class to the more powerful NIO API.

Checking File Permissions Using the File Class

The java.io.File class offers simple methods to check basic permissions of files and directories:

Example: Checking Permissions

import java.io.File;

public class FilePermissionCheck {
    public static void main(String[] args) {
        File file = new File("example.txt");

        System.out.println("Readable: " + file.canRead());
        System.out.println("Writable: " + file.canWrite());
        System.out.println("Executable: " + file.canExecute());
    }
}

Modifying File Permissions Using the File Class

The File class also allows changing permissions using:

These methods attempt to change the file’s permission for the owner only by default. You can optionally specify a second boolean parameter ownerOnly to restrict changes to the owner.

Example: Changing Permissions

import java.io.File;

public class FilePermissionModify {
    public static void main(String[] args) {
        File file = new File("example.txt");

        boolean readableSet = file.setReadable(true);
        boolean writableSet = file.setWritable(false);
        boolean executableSet = file.setExecutable(false);

        System.out.println("Readable set: " + readableSet);
        System.out.println("Writable set: " + writableSet);
        System.out.println("Executable set: " + executableSet);
    }
}

Note: These methods return true if the permission was successfully changed, or false otherwise. On some platforms or filesystems, permission changes may fail silently due to security policies or user rights.

Advanced Attributes and Permissions with NIO

Starting from Java 7, the java.nio.file package introduced a more comprehensive way to manage file permissions and attributes, including:

Using java.nio.file.attribute.PosixFilePermissions

On POSIX-compliant systems (like Linux and macOS), you can get and set file permissions using the PosixFilePermissions class.

Checking and Setting POSIX Permissions Example:

import java.nio.file.*;
import java.nio.file.attribute.*;
import java.io.IOException;
import java.util.Set;

public class PosixPermissionsExample {
    public static void main(String[] args) {
        Path path = Paths.get("example.txt");

        try {
            // Read current permissions
            Set<PosixFilePermission> permissions = Files.getPosixFilePermissions(path);
            System.out.println("Current permissions: " + PosixFilePermissions.toString(permissions));

            // Set new permissions: rw-r--r--
            Set<PosixFilePermission> newPermissions = PosixFilePermissions.fromString("rw-r--r--");
            Files.setPosixFilePermissions(path, newPermissions);

            System.out.println("Permissions updated.");

        } catch (UnsupportedOperationException e) {
            System.out.println("POSIX permissions not supported on this platform.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Notes:

Reading and Modifying Basic File Attributes

NIO also provides the BasicFileAttributes interface for reading attributes like:

Example to read these attributes:

import java.nio.file.*;
import java.nio.file.attribute.*;
import java.io.IOException;

public class BasicAttributesExample {
    public static void main(String[] args) {
        Path path = Paths.get("example.txt");

        try {
            BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);

            System.out.println("Creation Time: " + attrs.creationTime());
            System.out.println("Last Access Time: " + attrs.lastAccessTime());
            System.out.println("Last Modified Time: " + attrs.lastModifiedTime());
            System.out.println("Is Directory: " + attrs.isDirectory());
            System.out.println("Is Regular File: " + attrs.isRegularFile());

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Modifying File Timestamps

You can also update timestamps using Files.setAttribute():

import java.nio.file.*;
import java.nio.file.attribute.*;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

public class ModifyTimestampExample {
    public static void main(String[] args) {
        Path path = Paths.get("example.txt");

        try {
            FileTime now = FileTime.from(System.currentTimeMillis(), TimeUnit.MILLISECONDS);
            Files.setAttribute(path, "lastModifiedTime", now);
            System.out.println("Last modified time updated.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Managing File Owners

You can retrieve and modify file owners using FileOwnerAttributeView:

import java.nio.file.*;
import java.nio.file.attribute.*;
import java.io.IOException;

public class FileOwnerExample {
    public static void main(String[] args) {
        Path path = Paths.get("example.txt");

        try {
            FileOwnerAttributeView ownerView = Files.getFileAttributeView(path, FileOwnerAttributeView.class);

            System.out.println("Current owner: " + ownerView.getOwner());

            // Example: Set owner (requires appropriate permissions)
            // UserPrincipal newOwner = path.getFileSystem().getUserPrincipalLookupService().lookupPrincipalByName("username");
            // ownerView.setOwner(newOwner);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Recap

Index

3.5 Listing Files and Directories

Working with files and directories often requires listing their contents—for example, to display files in a folder, filter files by type, or perform operations recursively on subdirectories. Java's java.io.File class provides several convenient methods to list directory contents and apply filters.

Using the File Class to List Directory Contents

The File class provides two primary methods to list the contents of a directory:

Both methods return null if the File object is not a directory or an I/O error occurs.

Listing All Files and Directories

Here’s a simple example that lists all names in a directory using list():

import java.io.File;

public class ListDirectoryNames {
    public static void main(String[] args) {
        File dir = new File("myDirectory");

        // Check if directory exists and is a directory
        if (dir.exists() && dir.isDirectory()) {
            String[] contents = dir.list();

            if (contents != null) {
                for (String name : contents) {
                    System.out.println(name);
                }
            } else {
                System.out.println("Could not list directory contents.");
            }
        } else {
            System.out.println("Directory does not exist or is not a directory.");
        }
    }
}

Explanation:

Using listFiles() to Get File Objects

listFiles() returns an array of File objects, allowing you to inspect each entry's properties such as whether it is a file or directory, size, or last modified time.

import java.io.File;

public class ListDirectoryFiles {
    public static void main(String[] args) {
        File dir = new File("myDirectory");

        if (dir.exists() && dir.isDirectory()) {
            File[] files = dir.listFiles();

            if (files != null) {
                for (File file : files) {
                    if (file.isDirectory()) {
                        System.out.println("[DIR]  " + file.getName());
                    } else {
                        System.out.println("[FILE] " + file.getName());
                    }
                }
            } else {
                System.out.println("Could not list files.");
            }
        } else {
            System.out.println("Directory not found or invalid.");
        }
    }
}

This approach is more flexible because you can differentiate between files and directories and get more info.

Filtering Files with FilenameFilter and FileFilter

You can filter the listed files using two interfaces:

Example: Filter Files by Extension Using FilenameFilter

import java.io.File;
import java.io.FilenameFilter;

public class ListTxtFiles {
    public static void main(String[] args) {
        File dir = new File("myDirectory");

        FilenameFilter filter = new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return name.endsWith(".txt");  // Only accept .txt files
            }
        };

        String[] txtFiles = dir.list(filter);

        if (txtFiles != null) {
            for (String fileName : txtFiles) {
                System.out.println(fileName);
            }
        }
    }
}

This example lists only files ending with .txt.

Using a Lambda Expression (Java 8)

String[] txtFiles = dir.list((d, name) -> name.endsWith(".txt"));

Filtering with FileFilter

Using FileFilter gives access to the full File object:

import java.io.File;
import java.io.FileFilter;

public class ListLargeFiles {
    public static void main(String[] args) {
        File dir = new File("myDirectory");

        FileFilter filter = file -> file.isFile() && file.length() > 1_000_000; // Files larger than 1MB

        File[] largeFiles = dir.listFiles(filter);

        if (largeFiles != null) {
            for (File file : largeFiles) {
                System.out.println(file.getName() + " - " + file.length() + " bytes");
            }
        }
    }
}

Recursively Listing Files in Subdirectories

To list all files inside a directory and its subdirectories, you need to use recursion:

import java.io.File;

public class RecursiveFileLister {
    public static void listFilesRecursive(File dir) {
        if (dir == null || !dir.exists()) return;

        File[] files = dir.listFiles();
        if (files == null) return;

        for (File file : files) {
            if (file.isDirectory()) {
                System.out.println("[DIR]  " + file.getAbsolutePath());
                listFilesRecursive(file);  // Recursive call for subdirectory
            } else {
                System.out.println("[FILE] " + file.getAbsolutePath());
            }
        }
    }

    public static void main(String[] args) {
        File rootDir = new File("myDirectory");
        listFilesRecursive(rootDir);
    }
}

Explanation:

Using java.nio.file for Advanced Listing (Brief Intro)

While the File class is simple, the newer NIO API (java.nio.file) provides more powerful directory traversal using Files.walk() or Files.list(). This can be used to filter files more flexibly and perform parallel processing.

Example with Files.walk() (Java 8+):

import java.nio.file.*;
import java.io.IOException;

public class NIOFileWalkExample {
    public static void main(String[] args) {
        Path start = Paths.get("myDirectory");

        try {
            Files.walk(start)
                .filter(Files::isRegularFile)
                .filter(path -> path.toString().endsWith(".txt"))
                .forEach(System.out::println);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Recap

Index

3.6 File Deletion, Renaming, and Creation

Managing files often involves creating new files, renaming existing ones, or deleting files that are no longer needed. The Java java.io.File class provides straightforward methods to perform these file operations. However, because file operations depend on the underlying filesystem and operating system permissions, it’s important to handle errors carefully and understand the potential pitfalls.

Creating Files with createNewFile()

The method createNewFile() creates a new, empty file at the path specified by the File object.

Example: Creating a New File

import java.io.File;
import java.io.IOException;

public class FileCreationExample {
    public static void main(String[] args) {
        File file = new File("newFile.txt");

        try {
            if (file.createNewFile()) {
                System.out.println("File created successfully: " + file.getName());
            } else {
                System.out.println("File already exists: " + file.getName());
            }
        } catch (IOException e) {
            System.out.println("An error occurred while creating the file.");
            e.printStackTrace();
        }
    }
}

Best Practices and Pitfalls:

Deleting Files with delete()

The delete() method deletes the file or directory denoted by the File object.

Example: Deleting a File

import java.io.File;

public class FileDeletionExample {
    public static void main(String[] args) {
        File file = new File("oldFile.txt");

        if (file.delete()) {
            System.out.println("File deleted successfully.");
        } else {
            System.out.println("Failed to delete the file. It may not exist or is in use.");
        }
    }
}

Important Notes and Pitfalls:

Renaming and Moving Files with renameTo()

The method renameTo(File dest) renames the file to the new pathname specified by the dest File object. This method can also be used to move a file between directories.

Example: Renaming a File

import java.io.File;

public class FileRenameExample {
    public static void main(String[] args) {
        File oldFile = new File("oldName.txt");
        File newFile = new File("newName.txt");

        if (oldFile.renameTo(newFile)) {
            System.out.println("File renamed successfully.");
        } else {
            System.out.println("Failed to rename file.");
        }
    }
}

Example: Moving a File

File sourceFile = new File("file.txt");
File destinationFile = new File("subfolder/file.txt");

if (sourceFile.renameTo(destinationFile)) {
    System.out.println("File moved successfully.");
} else {
    System.out.println("Failed to move the file.");
}

Potential Issues with renameTo()

Best Practices for File Creation, Deletion, and Renaming

Recursively Deleting a Directory Example

Because File.delete() won’t delete non-empty directories, recursive deletion is needed:

public static boolean deleteDirectory(File directory) {
    if (directory.isDirectory()) {
        File[] entries = directory.listFiles();
        if (entries != null) {
            for (File entry : entries) {
                if (!deleteDirectory(entry)) {
                    return false;  // Failed to delete a file/subdir
                }
            }
        }
    }
    return directory.delete();
}

Use with care, as recursive deletion is destructive and irreversible.

Recap

Index