9

Weekly Rust Trivia: How to Get all Files in a Directory

 1 year ago
source link: https://www.thorsten-hans.com/weekly-rust-trivia-get-all-files-in-a-directory/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Weekly Rust Trivia: How to Get all Files in a Directory

Published Thu, May 11, 2023 / by Thorsten Hans / Estimated reading time: 2 min

Rust  / Weekly Rust Trivia

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),
    }
}

Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK