Rust File Handling
Programs save settings, store results, and read data from files. Rust's standard library offers tools for each task, and every operation returns a Result because disks fail, files go missing, and permissions block access. Treat file work like using a filing cabinet: open the drawer, read or write a page, and close the drawer.
Reading a Whole File
The function fs::read_to_string loads an entire text file into a String.
use std::fs;
fn main() {
match fs::read_to_string("notes.txt") {
Ok(content) => println!("{content}"),
Err(e) => println!("Cannot read file: {e}"),
}
}This approach suits small and medium files. Huge files deserve line-by-line reading, covered below.
Writing a Whole File
The function fs::write creates a file or replaces the content of an existing one.
use std::fs;
fn main() -> std::io::Result<()> {
fs::write("greeting.txt", "Hello, file!")?;
println!("File saved");
Ok(())
}Existing content disappears without a warning, so choose file names with care.
The File Type
Use File when you need more control than the one-line helpers give.
use std::fs::File;
use std::io::Write;
fn main() -> std::io::Result<()> {
let mut file = File::create("log.txt")?;
writeln!(file, "Line one")?;
writeln!(file, "Line two")?;
Ok(())
}
File::create --> file handle --> writeln! --> data on disk
^
file closes automatically when
the handle leaves scope
Appending to a File
The OpenOptions builder lets you pick the mode. The append option adds text to the end and keeps existing lines.
use std::fs::OpenOptions;
use std::io::Write;
fn main() -> std::io::Result<()> {
let mut file = OpenOptions::new()
.create(true)
.append(true)
.open("log.txt")?;
writeln!(file, "New entry")?;
Ok(())
}| Option | Effect |
|---|---|
| read(true) | Allows reading |
| write(true) | Allows writing |
| append(true) | Adds to the end |
| create(true) | Makes the file when missing |
| truncate(true) | Clears old content on open |
Reading Line by Line
A BufReader collects chunks of data in memory and hands out one line at a time. Memory use stays low even for very large files.
use std::fs::File;
use std::io::{BufRead, BufReader};
fn main() -> std::io::Result<()> {
let file = File::open("log.txt")?;
let reader = BufReader::new(file);
for (number, line) in reader.lines().enumerate() {
println!("{}: {}", number + 1, line?);
}
Ok(())
}
1: Line one 2: Line two 3: New entry
Working with Paths
The Path and PathBuf types describe file locations in a way that works across Windows, macOS, and Linux.
use std::path::Path;
fn main() {
let path = Path::new("data").join("report.txt");
println!("{}", path.display());
println!("{}", path.exists());
println!("{:?}", path.extension());
}The join method inserts the correct separator for the operating system, so avoid typing slashes by hand.
Folders and Cleanup
use std::fs;
fn main() -> std::io::Result<()> {
fs::create_dir_all("output/reports")?; // make folders
fs::copy("log.txt", "output/log_copy.txt")?;
fs::rename("output/log_copy.txt", "output/log_old.txt")?;
fs::remove_file("output/log_old.txt")?; // delete a file
for entry in fs::read_dir("output")? {
let entry = entry?;
println!("{}", entry.file_name().to_string_lossy());
}
Ok(())
}Handling Missing Files Gracefully
The error value reveals the cause. A program can react differently to a missing file than to a permission problem.
use std::fs;
use std::io::ErrorKind;
fn main() {
match fs::read_to_string("settings.txt") {
Ok(text) => println!("Loaded {} bytes", text.len()),
Err(e) if e.kind() == ErrorKind::NotFound => {
println!("No settings file found, using defaults");
}
Err(e) => println!("Unexpected problem: {e}"),
}
}A Small Complete Program
The program below counts the words in a file.
use std::fs;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let text = fs::read_to_string("notes.txt")?;
let words = text.split_whitespace().count();
let lines = text.lines().count();
println!("{lines} lines, {words} words");
Ok(())
}Safety and Privacy Tips
- Never trust file names typed by outside users without checking them.
- Avoid saving passwords or private details in plain text files.
- Write to a temporary file, rename it afterward, so a crash cannot leave half-written data.
- Check that the target folder exists before writing.
Practice Ideas
- Write a program that saves a list of names to a file and loads them back.
- Build a simple diary that appends a line each time it runs.
- Count the lines that contain a chosen word in a text file.
Choosing the Right Tool
Pick the shortest helper that fits the job. Whole-file helpers suit configuration files and notes. A buffered reader suits logs and large data sets. The builder type suits special modes such as appending. Matching the tool to the task keeps code short and memory use low.
Key Points
fs::read_to_stringandfs::writehandle whole files in one call.File,OpenOptions, andBufReadergive finer control.- Every file action returns a
Result, so handle failures withmatchor?. - Use
Pathfor portable file locations.
