Skip to main content
Rust Programming
CHAPTER 20 Beginner

File Handling in Rust

Updated: May 18, 2026
5 min read

# CHAPTER 20

File Handling in Rust

1. Chapter Introduction

Any robust application, whether a database engine or a simple CLI, needs to persist data. In this chapter, we will learn how to interact with the file system using Rust's standard library (std::fs). We will combine our knowledge of String manipulation and the Result enum to read, write, and append data safely.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Read the entire contents of a file into a String.
  • Write new data to a file (overwriting existing content).
  • Append data to an existing file.
  • Understand the std::fs and std::io modules.

3. Reading a File

The easiest way to read a file in Rust is to use the fs::read_to_string function. It opens the file, reads all the UTF-8 text into a String, and closes the file automatically.
rust
1234567891011
use std::fs;

fn main() {
    // Attempt to read the file. Returns a Result<String, Error>
    let content = fs::read_to_string("hello.txt");

    match content {
        Ok(text) => println!("File contains:\n{}", text),
        Err(e) => println!("Failed to read file: {}", e),
    }
}

4. Writing to a File

To write data, we can use fs::write. *Warning: If the file exists, this will completely overwrite it! If it does not exist, it will create it.*
rust
1234567891011
use std::fs;

fn main() {
    let data = "This is some new data we are writing to the disk!";
    
    // Write data. Returns a Result<(), Error>
    match fs::write("output.txt", data) {
        Ok(_) => println!("Successfully wrote to the file."),
        Err(e) => println!("Error writing: {}", e),
    }
}

5. Appending to a File

If you are building a log file, you don't want to overwrite the data every time; you want to *append* to the end. For this, we need more control. We use OpenOptions.
rust
12345678910111213141516171819202122
use std::fs::OpenOptions;
use std::io::Write; // Needed for the .write_all() trait method

fn main() {
    // Configure how we open the file
    let file_result = OpenOptions::new()
        .create(true) // Create if it doesn't exist
        .append(true) // Append to the end
        .open("logs.txt");

    match file_result {
        Ok(mut file) => {
            // Write the data as bytes
            if let Err(e) = file.write_all(b"User logged in.\n") {
                println!("Failed to write to file: {}", e);
            } else {
                println!("Log updated.");
            }
        }
        Err(e) => println!("Failed to open file: {}", e),
    }
}

6. Mini Project: Notes Manager

Let's build a small application that asks the user for a note and saves it permanently to a notes.txt file using the ? error propagation operator we learned in Chapter 15.
rust
123456789101112131415161718192021222324252627
use std::fs::OpenOptions;
use std::io::{self, Write};

// Function returns a Result so we can use '?'
fn save_note(note: &str) -> io::Result<()> {
    let mut file = OpenOptions::new()
        .create(true)
        .append(true)
        .open("notes.txt")?; // The '?' handles the Err automatically!

    file.write_all(note.as_bytes())?;
    file.write_all(b"\n")?; // Add a newline

    Ok(()) // Return success
}

fn main() {
    println!("Enter a note to save:");
    let mut input = String::new();
    
    io::stdin().read_line(&mut input).expect("Failed to read input");

    match save_note(input.trim()) {
        Ok(_) => println!("Note saved successfully!"),
        Err(e) => println!("Critical Error: Could not save note. {}", e),
    }
}

7. Common Mistakes

  • Forgetting use std::io::Write;: If you try to use .write_all(), the compiler will complain that the method doesn't exist unless you bring the Write trait into scope!
  • Pathing Issues: Expecting "file.txt" to be relative to the .rs file. It is actually relative to where you execute cargo run (usually the root directory of the project).

8. Best Practices

  • Never use unwrap() for File I/O: File operations are the most likely things to fail in a program (due to permissions, missing files, or full hard drives). Always handle the Result.

9. Exercises

  1. 1. Write a program that uses fs::write to create a file named secret.txt containing the word "Rust".
  1. 2. Use fs::read_to_string to read secret.txt and print the contents to the console.

10. MCQs with Answers

Question 1

Which standard library module handles file system operations?

Question 2

What is the simplest function to read an entire file into a String?

Question 3

If fs::read_to_string fails (e.g., file not found), what does it return?

Question 4

What happens if you use fs::write() on a file that already exists?

Question 5

To append data to an existing file, which struct must you use to configure the file opening?

Question 6

What trait must be brought into scope (use std::io::Write;) to use the .write_all() method?

Question 7

When you pass a string to .write_all(), what format must it be in?

Question 8

Why is it dangerous to use .unwrap() on file operations in a production app?

Question 9

What does the b prefix mean in b"Hello"?

Question 10

Where does cargo run expect "notes.txt" to be located by default?

11. Interview Questions

  • Q: Explain how Rust handles the closing of file handles. Do you need to call file.close()? (Answer: No, Rust's Ownership rules automatically drop the file handle and close the OS resource when the file variable goes out of scope).

12. Summary

File handling in Rust is designed around explicit error handling. The std::fs module provides rapid functions for simple tasks, while OpenOptions grants granular control for logging and appending. Coupled with Rust's automatic memory management dropping the file handle safely, your I/O code is both expressive and leak-free.

13. Next Chapter Recommendation

In the real world, you rarely process data in single variables; you process lists of data. In Chapter 21: Closures and Iterators, we will learn functional programming paradigms to transform massive datasets cleanly and efficiently.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·