How to list files in a directory in Rust: a step-by-step tutorial

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: why might you need a file list in Rust?

\n\n

Imagine: you are writing a backup utility, a log analyzer, or a simple file manager in Rust. And then a basic but critical task arises — to get a list of all files in a specified directory. It seems simple, right? But in Rust, with its strict typing and ownership system, even such a simple operation hides several pitfalls.

\n\n

The question «How can I list files of a directory in Rust?» is one of the most popular on Stack Overflow (thousands of views!). And this is no coincidence: beginners often stumble over std::fs::read_dir, get confused with iterators, and forget about error handling. In this tutorial, I will show you two working approaches: simple (only files in one folder) and advanced (recursive traversal of all subdirectories). Let's go!

\n\n

1. Preparation: create a new project

\n\n

Before writing code, let's create a new binary project. Open your terminal and run:

\n\n
cargo new list_files_rs\ncd list_files_rs
\n\n

Now open src/main.rs — this is where we will write all the code. To start, we won't need any external dependencies, only the Rust standard library — std.

\n\n

2. The simplest way: std::fs::read_dir

\n\n

The std::fs::read_dir function returns an iterator over the entries in a directory. Each entry is a DirEntry, which contains the name, path, type, and metadata of the file. Let's write a basic example:

\n\n
use std::fs;\nuse std::path::Path;\n\nfn main() -> Result<(), Box<dyn std::error::Error>> {\n    let path = Path::new("."); // current directory\n\n    // Read the contents of the folder\n    let entries = fs::read_dir(path)?;\n\n    for entry in entries {\n        let entry = entry?; // unpack the Result\n        let path = entry.path();\n\n        // Check that it is a file (not a directory)\n        if path.is_file() {\n            println!("{}", path.display());\n        }\n    }\n\n    Ok(())\n}
\n\n

What is happening here?

\n
    \n
  • fs::read_dir(path) — opens the directory and returns a ReadDir (iterator).
  • \n
  • We iterate over each entry. Each call to next() returns a Result<DirEntry> — hence the need for entry?.
  • \n
  • entry.path() returns the full path to the file/folder.
  • \n
  • The path.is_file() method filters out subdirectories.
  • \n
\n\n

Run the code with the command cargo run — you will see a list of files in the project root (e.g., Cargo.toml, src/main.rs).

\n\n

2.1. Filtering by extension

\n\n

Often you need to get only specific files, for example, only .rs or .txt. Let's add a filter:

\n\n
use std::fs;\nuse std::path::Path;\n\nfn main() -> Result<(), Box<dyn std::error::Error>> {\n    let path = Path::new(".");\n\n    for entry in fs::read_dir(path)? {\n        let entry = entry?;\n        let path = entry.path();\n\n        // Check that it is a file and the extension is .rs\n        if path.is_file() && path.extension().map_or(false, |ext| ext == "rs") {\n            println!("{}", path.display());\n        }\n    }\n\n    Ok(())\n}
\n\n

The trick with map_or is needed to safely handle the case when a file has no extension — path.extension() returns Option<&OsStr>.

\n\n

3. Recursive traversal: looking into all subfolders

\n\n

A simple read_dir does not go into subdirectories. If you need to collect all files recursively (e.g., for finding duplicates), you'll have to write your own recursive function. Here is an elegant solution:

\n\n
use std::fs;\nuse std::path::Path;\n\nfn visit_dirs(dir: &Path, depth: usize) -> Result<(), Box&l                

Blogs

Book Recommendations