File System Operations

read_dir()

std::fs::read_dir(path) -> io::Result<ReadDir> opens a directory at path and returns a ReadDir iterator that yields io::Result<DirEntry> for each child entry inside the directory (automatically excluding the special . current-directory and .. parent-directory entries).

Why read_dir Has Two Layers of io::Result

Notice that both fs::read_dir(path) and each item yielded by ReadDir return an io::Result:

  1. Outer io::Result<ReadDir>: Fails immediately if path does not exist (NotFound), is not a directory (NotADirectory), or the process lacks read permission on path (PermissionDenied).
  2. Inner Iterator<Item = io::Result<DirEntry>>: Fails if an OS I/O error occurs mid-iteration while reading subsequent directory blocks from disk or a network filesystem.

Methods on std::fs::DirEntry

DirEntry Method Signature Extra OS Syscall on Unix/Windows? Description
.path(&self) pub fn path(&self) -> PathBuf No Returns the full path (joining the argument passed to read_dir with .file_name())
.file_name(&self) pub fn file_name(&self) -> OsString No Returns only the bare filename component ("Cargo.toml")
.file_type(&self) pub fn file_type(&self) -> io::Result<FileType> No (on Windows and most Unix filesystems) Returns FileType (.is_dir(), .is_file(), .is_symlink()) without following symlinks
.metadata(&self) pub fn metadata(&self) -> io::Result<Metadata> No on Windows; lstat syscall on Unix Returns file size, permissions, and timestamps (without following symlinks)
use std::fs;
use std::io;

fn main() -> io::Result<()> {
    let dir = std::env::temp_dir().join("rust_ch50_readdir_demo");
    fs::create_dir_all(&dir)?;
    fs::write(dir.join("config.toml"), "port = 8080\n")?;
    fs::create_dir_all(dir.join("logs"))?;

    let mut entries: Vec<(String, &'static str)> = Vec::new();

    for entry_res in fs::read_dir(&dir)? {
        let entry = entry_res?;
        let name = entry.file_name().to_string_lossy().into_owned();
        let ft = entry.file_type()?;

        let kind = if ft.is_dir() {
            "dir"
        } else if ft.is_file() {
            "file"
        } else {
            "symlink/other"
        };
        entries.push((name, kind));
    }

    entries.sort();
    for (name, kind) in entries {
        println!("{:<14} ({})", name, kind);
    }

    fs::remove_dir_all(&dir)?;
    Ok(())
}
config.toml    (file)
logs           (dir)