Knowing how to read and write files can be useful for various purposes. In Rust, this task is done using the file system module (std::fs) in the standard library. In this article, I'll give you an overview on how to use this module.
To demonstrate this task, I prepared example code which is also available on GitHub.
Preparation
When using Rust, a function that fails returns the Result type. The file system module in particular returns the specialized type std::io::Result<T, Error>. With this knowledge, you can return the same type from the main()
function:
fn main() -> std::io::Result<()> {
/* ...code comes here... */
Writing Rust files
Performing file I/O-operations in Rust is relatively easy. Writing to a file can be simplified to one line:
use std::fs;
fs::write("favorite_websites.txt", b"opensource.com")?;
Ok(())
Using the error propagation operator (?)
, the error information gets passed on to the calling function where the error can subsequently be handled. As main()
is the only other function in the call stack, the error information gets passed on to the console output in case the write operation failed.
The syntax of the fs::write function is quite forward. The first argument is the file path, which must be the type std::path::Path. The second argument is the content, which is actually a slice of bytes ([u8]
). Rust converts the arguments passed into the correct type. Luckily, these types are basically the only types dealt with in the following examples.
A more concise access of the write operation can be achieved using the file descriptor type std::fs::File:
let mut file = fs::File::create("favorite_websites.txt")?;
file.write_all(b"opensource.com\n")?;
Ok(())
As the file type implements the Write trait, it is possible to use the associated methods to write to the file. However, the create
method can overwrite an already existing file.
To get even more control of the file descriptor, the type std::fs::OpenOptions must be used. This provides opening modes similar to the ones in other languages:
let mut file = fs::OpenOptions::new()
.append(true)
.open("favorite_websites.txt")?;
file.write_all(b"sourceforge.net\n")?;
Reading Rust files
What applies to writing also applies to reading. Reading can also be done with a simple one-line of code:
let websites = fs::read_to_string("favorite_websites.txt")?;
The above line reads the content of the file and returns a string. In addition to reading a string, there is also the std::fs::read function which reads the data into a vector of bytes if the file contains binary data.
The next example shows how to read the content of the file into memory and subsequently print it line by line to a console:
let file = fs::File::open("favorite_websites.txt")?;
let lines = io::BufReader::new(file).lines();
for line in lines {
if let Ok(_line) = line {
println!(">>> {}", _line);
}
}
Summary
If you are already familiar with other programming languages, you may have noticed that there is no close-
function (or something similar) that releases the file handle. In Rust, the file handle is released as soon as the related variable goes out of scope. To define the closing behavior, a scope ({ })
around the file representation can be applied. I recommend that you get familiar with Read and Write trait as you can find this trait implemented in many other types.
Comments are closed.