One-shot helpers vs streaming
`std::fs::read`, `read_to_string`, and `write` are convenience helpers that open, read or write everything, and close the file in a single call. They're the right tool for small files — config, HTML templates, single-shot tools. For anything large, prefer `File::open` plus a `BufReader` / `BufWriter` and stream byte-by-byte to keep memory bounded.
Paths and platform behaviour
All filesystem APIs take `AsRef<Path>`. `std::path::Path` and `PathBuf` are the canonical path types — they handle separator normalisation across platforms and have helpers like `extension`, `file_stem`, `parent`, and `join`. Avoid raw string concatenation when building paths; the `join` method handles separators correctly on every OS.
For deeper background, see a complete cheat-sheet of std collection complexities for the broader context behind this section.
Atomic writes and crash safety
`std::fs::write` is not atomic. If the program crashes mid-write the file is left in an undefined state. The portable atomic-write recipe is: write to a sibling temp file, fsync it, then `rename` over the destination. The `rename` on POSIX is atomic, and on Windows since `MoveFileExW` is too. Crates like `tempfile` and `atomicwrites` package this pattern.
Metadata and permissions
`std::fs::metadata` and `symlink_metadata` return a `Metadata` struct with file type, length, modification time, and platform-specific permissions. Permissions are abstracted via `Permissions::readonly()` for portability; for full POSIX modes you need the `std::os::unix::fs::PermissionsExt` extension trait.
For deeper background, see the official Rust API guidelines for module-level design for the broader context behind this section.
Directories: read_dir and walking
`std::fs::read_dir` returns an iterator of `Result<DirEntry>`. It does not recurse — for recursive walks bring in `walkdir`, which handles symlink loops, errors, and ordering. `create_dir_all` makes a path including all missing parents in one call; `remove_dir_all` deletes recursively.