How to delete a file or a whole directory
Short answer: fs::remove_file("path") deletes one file. fs::remove_dir("path") deletes a directory — but only while it’s empty. fs::remove_dir_all("path") deletes a directory and everything inside it. All three return io::Result, and none of them ask for confirmation: there’s no recycle bin in the standard library, and what’s gone stays gone.
From a fresh project — cargo new delete-demo, then replace the contents of src/main.rs with each block below and run it with cargo run. Each block creates the files and directories it works on, so it runs on its own and in any order. Paths are relative to the directory you run from, which under cargo run is the project root.
Deleting a file with fs::remove_file
Section titled “Deleting a file with fs::remove_file”use std::fs;
fn main() -> std::io::Result<()> { fs::write("notes.txt", "meeting at ten\n")?; fs::remove_file("notes.txt")?; println!("still there: {}", fs::metadata("notes.txt").is_ok()); Ok(())}still there: falseDeleting is unlinking: the name disappears from its directory. The path has to be a file — fs::remove_file on a directory is an error too (on this machine, Operation not permitted (os error 1); the exact wording is platform-specific). Directories get their own functions below.
The missing file is an error
Section titled “The missing file is an error”use std::fs;use std::io::ErrorKind;
fn main() { match fs::remove_file("missing.txt") { Ok(()) => println!("deleted"), Err(e) if e.kind() == ErrorKind::NotFound => { println!("nothing to delete: {e}"); } Err(e) => println!("something else: {e}"), }}nothing to delete: No such file or directory (os error 2)NotFound is the one kind you can read backwards from: the standard library promises that a NotFound error means the path didn’t exist. The reverse doesn’t hold — an existing path can still fail to delete because of permissions — so this match means “there was nothing to do”, not “everything went fine”.
If you’re about to add an existence check before deleting: the check and the delete can race, and you end up handling NotFound anyway. Matching the error costs one branch and has no gap. The next page is about checking paths, so it stops there.
Directories: remove_dir and remove_dir_all
Section titled “Directories: remove_dir and remove_dir_all”use std::fs;
fn main() -> std::io::Result<()> { fs::create_dir_all("project/src")?; fs::write("project/src/main.rs", "fn main() {}\n")?; match fs::remove_dir("project") { Ok(()) => println!("removed"), Err(e) => println!("remove_dir refused: {e}"), } fs::remove_dir_all("project")?; println!("still there: {}", fs::metadata("project").is_ok()); Ok(())}remove_dir refused: Directory not empty (os error 66)still there: falsefs::remove_dir is the directory counterpart of remove_file, and it refuses anything non-empty — its error kind is DirectoryNotEmpty. The message and the error number are platform-specific; the kind isn’t. fs::remove_dir_all removes the directory and everything under it, files and subdirectories alike, so the usual rm -rf warning applies: it will happily delete a tree you pointed at by mistake. A path that doesn’t exist is a NotFound error for both functions, same as for remove_file.
What is permanent
Section titled “What is permanent”Nothing here goes to a recycle bin. No confirmation, no undo, and no standard-library way back.
One subtlety is visible on Unix, where deletion really is just an unlink:
use std::fs;use std::io::Read;
fn main() -> std::io::Result<()> { fs::write("open.txt", "still being read\n")?; let mut f = fs::File::open("open.txt")?; fs::remove_file("open.txt")?; println!("name gone: {}", fs::metadata("open.txt").is_err()); let mut buf = String::new(); f.read_to_string(&mut buf)?; println!("handle still reads: {:?}", buf); Ok(())}name gone: truehandle still reads: "still being read\n"The name is gone, but the handle opened before the delete still reads the contents. On Unix the data isn’t released until the last name and the last handle are gone. The standard library only promises this loosely — there’s “no guarantee that the file is immediately deleted”, because on some platforms other open file descriptors prevent immediate removal — so when the disk space actually comes back is a platform question, not a Rust one.
If the deletion needs to be recoverable, don’t use remove_file: move the file into the user’s trash instead. The standard library can’t do that, so it means a third-party crate.
Related
Section titled “Related”- How to copy or move a file —
fs::rename, the non-destructive cousin - Reading and writing files — the rest of the chapter