Weekly Rust Trivia is a problem-oriented series of articles that assist developers while learning Rust. Every article solves simple, everyday development tasks using the Rust standard library or leveraging popular and proven crates.
Question: How to get a vector (Vec<String>
) containing all filenames of a particular directory in Rust?
We can use the fs
and io
modules from Rust standard library this trivia.
use std::{fs, io};
fn get_files_in_directory(path: &str) -> io::Result<Vec<String>> {
// Get a list of all entries in the folder
let entries = fs::read_dir(path)?;
// Extract the filenames from the directory entries and store them in a vector
let file_names: Vec<String> = entries
.filter_map(|entry| {
let path = entry.ok()?.path();
if path.is_file() {
path.file_name()?.to_str().map(|s| s.to_owned())
} else {
None
}
})
.collect();
Ok(file_names)
}
In this example, we pass the path of the desired directory as argument to the get_files_in_directory
function. We then use the fs::read_dir()
method to get a list of all entries in the directory, which returns a std::fs::ReadDir
iterator. We use the filter_map()
method to filter out any None
values from the iterator, then check whether each entry is a file or a directory using the is_file()
method of the std::path::Path
struct.
If the entry is a file, we extract the filename using the file_name()
method and convert it to a String using the to_str()
and to_owned()
methods. If the entry is a directory, we return None
to filter it out of the iterator. Finally, we use the collect()
method to collect the filenames into a Vec<String>
.
We can call the get_files_in_directory
function as shown here:
fn main() {
match get_files_in_folder("/tmp") {
Ok(file_names) => {
for file_name in file_names {
println!("{}", file_name);
}
}
Err(e) => println!("Error: {}", e),
}
}
Community Feedback
As suggested by Thomas Darimont here, it may be more convinient to return a Vector of std::path::PathBuf
which allows further processing for every item. See the following implementation of get_files_in_folder
returning a Vec<PathBuf>
. Basically, It allows the callee to do things like:
- check if
PathBuf
is a directory or a file - check if
PathBuf
is a symlink - do even more complex examination by consulting
PathBuf::metadata()
use std::{fs, io, path::PathBuf};
fn get_files_in_folder(path: &str) -> io::Result<Vec<PathBuf>> {
let entries = fs::read_dir(path)?;
let all: Vec<PathBuf> = entries
.filter_map(|entry| Some(entry.ok()?.path()))
.collect();
Ok(all)
}
The alternative implementation can be used like this:
fn main() {
match get_files_in_folder("/tmp") {
Ok(files) => {
for file in files {
if file.is_dir() {
println!("{} is a directory", file.display());
continue;
}
if file.is_symlink() {
println!("{} is a symlink", file.display());
continue;
}
let Ok(m) = file.metadata() else {
println!("Could not get metadata for {}", file.display());
continue;
};
if m.len() == 0 {
println!("{} is an empty file", file.display());
continue;
}
println!("{} is a file", file.display());
}
}
Err(e) => println!("Error: {}", e),
}
}