File reading is one of the most fundamental operations in programming, and Rust provides several efficient and convenient ways to read from a file line by line.
In this tutorial, we’ll explore the several techniques to read from a file line by line in Rust. We’ll cover the pros and cons of each method and provide examples that demonstrate how to use them in practice.
Requirements:
To follow this tutorial, you will require the following:
- Rust development environment on your system
- A code editor
- Basic Rust development knowledge
When you meet the given requirements, we can proceed with the essential steps.
Project Setup
The first step is to setup the Rust project and where to store the source code. For that, we use the cargo command as follows:
This initializes a new project with the specified file. It also creates the src where we can store the source code for the application. Finally, it also generates a “Cargo.toml” file which we can use to manage the project.
Next, navigate to the project directory and create a new assets directory:
Next, create a new “txt” file and add the content that you wish to read:
Edit the “file.txt” and add the lines as follows:
PostgreSQL
MariaDB
Oracle
MS SQL Server
We then use the Rust language to read the lines from the previous file.
Method 1: Using the BufReader Method
The most common and efficient method that we can use to read a file line by line in the Rust programming language is the BufReader method. The std::io::BufReader struct and the “lines” method allow us to iterate over the file lines.
An example code is as follows:
use std::io::{BufRead, BufReader};
fn main() -> std::io::Result<()> {
let file = File::open("./assets/file.txt")?;
let reader = BufReader::new(file);
for line in reader.lines() {
println!("{}", line?);
}
Ok(())
}
In this example, we first open the “file.txt” file using the File::open.
We then create a BufReader for the file which buffers the input and provides an iterator over the lines using the “lines” method. We then loop over each line and print it to the console using a “for” loop.
Method 2: Using the Read_Lines() Method
As you might noticed, once we create the BufReader for the target file, we can use the “lines” method to iterate over the lines of the target file. This method is rapid and convenient. However, it provides little control over the reading process.
This is where the second method comes into play. We can use the read_lines() method to define how to read the target file.
An example demonstration is as follows:
use std::io::{BufRead, BufReader};
fn main() -> std::io::Result<()> {
let file_path = "./assets/file.txt";
read_lines_from_file(file_path)?;
Ok(())
}
fn read_lines_from_file(file_path: &str) -> std::io::Result<()> {
let file = File::open(file_path)?;
let mut reader = BufReader::new(file);
let mut line = String::new();
loop {
let len = reader.read_line(&mut line)?;
if len == 0 {
break;
}
println!("{}", line);
line.clear();
}
Ok(())
}
As you can guess, this function behaves similarly to the “lines” method. In addition, it provides granular control over how we read the file.
Method 3: Using the Next Method
What if you still wish to use the lines() method and still have a similar level of control? This is where the third method comes into play.
This method involves creating a BufReader for the file and using its “lines” method to create an iterator of lines. Then, we use the “next” method of the iterator to get each line of the file.
An example code is as follows:
use std::io::{BufRead, BufReader};
fn main() -> std::io::Result<()> {
let file_path = "./assets/file.txt";
read_lines_from_file(file_path)?;
Ok(())
}
fn read_lines_from_file(file_path: &str) -> std::io::Result<()> {
let file = File::open(file_path)?;
let reader = BufReader::new(file);
let mut lines = reader.lines();
while let Some(line) = lines.next() {
println!("{}", line?);
}
Ok(())
}
It works similarly to the “lines” method but provides more control using the “next” method.
Method 4: Creating the File and BufReader Struct Separately
The “next” method is also similar to the “lines” method. However, instead of a direct call, we create the file and BufReader struct separately. This method involves an extra layer of buffering when reading the file.
An example code is as follows:
use std::io::{BufRead, BufReader};
fn main() -> std::io::Result<()> {
let file_path = "./assets/file.txt";
read_lines_from_file(file_path)?;
Ok(())
}
fn read_lines_from_file(file_path: &str) -> std::io::Result<()> {
let file = File::open(file_path)?;
let reader = BufReader::new(file);
for line in reader.lines() {
println!("{}", line?);
}
Ok(())
}
Conclusion
There you have it—four main ways of reading a file line by line in the Rust programming language.