Directories

Use the following recipes to create, list, delete, and recursively traverse directories.

Get the Current Working Directory

std cat~filesystem

std::env::current_dir returns the current working directory as a Result<PathBuf>:

//! Demonstrates how to get the current working directory.
use std::env;
use std::path::PathBuf;

use anyhow::Result;

fn main() -> Result<()> {
    let cwd: PathBuf = env::current_dir()?;
    println!("The current directory is {}", cwd.display());
    Ok(())
}

Create, List Contents of, and Remove Directories

std cat~filesystem

The following example demonstrates basic operations on directories - creating & removing (recursively if needed), listing contents:

use std::fs;
use std::path::Path;

fn main() -> std::io::Result<()> {
    // 1. Create a directory:
    let path = Path::new("./example_dir");
    if !path.exists() {
        fs::create_dir(path)?;
        // This function will return an error e.g. if the parent directory
        // doesn't exist, if the directory already exists, or if
        // permissions are lacking.
        println!("Directory 'example_dir' created successfully!");
    } else {
        println!("Directory 'example_dir' already exists.");
    }

    // 2. Remove it. The directory must be empty:
    fs::remove_dir(path)?;
    println!("'{}' successfully removed.", path.display());

    // 3. Create a directory and any of its missing parents:
    let path = "./temp/my_files/subfolder";
    fs::create_dir_all(path)?; // Creates 'temp', 'temp/my_files', and 'temp/my_files/subfolder' if they don't exist.
    // You can also use `DirBuilder`:
    // std::fs::DirBuilder::new()
    //     .recursive(true)
    //     .create(path)?;

    // 4. Create a few files for the next step.
    // `write` creates a file if it does not exist, and will entirely replace
    // its contents if it does.
    fs::write("./temp/my_files/file1.txt", "Hello")?;
    fs::write("./temp/my_files/subfolder/file2.log", "World")?;

    // 5. List the contents of a directory:
    println!("Reading contents of 'my_files':");
    // `read_dir` returns an iterator over the directory's entries.
    // Note that the order in which `read_dir` returns entries is not
    // guaranteed.
    // Use recursion to list the contents of all (sub)directories.
    for entry in fs::read_dir("./temp/my_files")? {
        let entry = entry?; // Handle potential error for each entry.
        let path = entry.path();

        if path.is_dir() {
            print!("- (Directory) {} ", path.display());
        } else {
            print!("- (File)      {} ", path.display());
        }
    }

    // 6. `std::fs::remove_dir_all` removes a directory at a given path, after
    // removing all its contents - similar to `rm -rf` on Unix.
    // Note that `remove_dir_all` will fail if `remove_dir` or `remove_file`
    // fail on any constituent paths. The directory to be deleted must
    // therefore exist. This function does not follow symbolic links and
    // will simply remove the symbolic link itself.
    fs::remove_dir_all("./temp/my_files")?;
    Ok(())
}

Remove a Directory and its Contents with remove_dir_all

remove_dir_all remove_dir_all~crates.io remove_dir_all~repo remove_dir_all~lib.rs cat~filesystem

The remove_dir_all library provides an alternative implementation of std::fs::remove_dir_all from the Rust std library.

In particular, its optional 'parallel' feature parallelizes the deletion. This is useful when high syscall latency is occurring, such as on Windows or network file systems.

//! Add to `Cargo.toml`:
//! ```toml
//! remove_dir_all = { version = "1.0.0", features = [ "parallel" ] }
//! ```

use std::io;

use remove_dir_all::remove_dir_all;

fn main() -> io::Result<()> {
    // Create a directory structure for demonstration purposes
    // (if it doesn't exist already).
    let path = "temp/example_dir/sub_dir";
    std::fs::create_dir_all(path)?;
    std::fs::write("temp/example_dir/file1.txt", "Hello, world!")?;
    std::fs::write("temp/example_dir/sub_dir/file2.txt", "Rust is awesome!")?;

    // Now, remove the subdirectory and all of its contents.
    match remove_dir_all(path) {
        Ok(_) => println!(
            "Directory 'sub_dir' and all contents removed successfully!"
        ),
        Err(e) => eprintln!("Failed to remove directory: {e}"),
    }
    // Beware:
    // - Calling this on a non-directory (e.g. a symlink to a directory)
    // will error.
    // - It assumes both that the caller has permission to delete
    // the files, and that they don't have permission to change permissions to
    // be able to delete the files: no ACL or chmod changes are made during
    // deletion.

    // Security note: The functions `remove_dir_all`, and related
    // `remove_dir_contents`, and `ensure_empty_dir` are intrinsically
    // sensitive to file system races. The crate authors recommend using the
    // `RemoveDir` trait instead. This allows callers to be more confident
    // that what is deleted is what was requested even in the presence of
    // (malicious) actors changing the filesystem concurrently:
    //
    // let mut dir = std::fs::File::open("temp/")?;
    // use remove_dir_all::RemoveDir;
    // dir.remove_dir_contents(None)?;
    Ok(())
}
  • Directory Traversal.
  • Paths.
  • Symbolic Links.
  • User Directories.