How to fetch unknown filetype extensions in rust

Viewed 56

Hey so I'm trying to make an automatic file sorting program in rust. I need it to read the filename in the users downloads folder and then move the file to a separate folder accordingly (jpg png to the "pictures" folder etc)

And I've been having some issues with fetching and using the filetype extensions; I have been able to find a way to grab the entire filename but not filter out the name so its just the extensions now.

I know this code isn't right and currently doesn't compile but this is a demonstration of the vague idea I'm after. I'm unsure if its even possible at least with rust.

use std::{thread,fs, time::Duration, io::Write};
// use chrono::Utc;
// use colour::*;


fn cls(){
    print!("{esc}c", esc = 27 as char);
}

fn credits(){
    print!("{esc}c", esc = 27 as char);
    println!("Made by Xanthus");
    println!("Check out my other works at https://github.com/Xanthus58");
    println!("Email me at 'Xanthus58@protonmail.com'");
    println!("You can see more information on my website https://xanthus58.github.io/Xanthus58/");
    
    let mut input = String::new();
    println!("Press Enter To Return");
    std::io::stdin().read_line(&mut input).unwrap();
    let minputod_yn = input.trim();
}

fn main() {
    loop{
        cls();
        let paths = fs::read_dir("./").unwrap();
        let mut file = "";
        for file_name in paths {
            let file_name = file_name.unwrap().path().display();
            //println!("Name: {}", file_name.unwrap().path().display());
            if file_name == ".jpg" || file_name == ".png"{
                let picture_dir = "Downloaded Pictures";
                fs::create_dir_all(picture_dir).unwrap();
                std::fs::rename(file_name, format!("{picture_dir}/{file_name}")).unwrap();
                println!("Name: {} Moved to {}", file_name.unwrap().path().display(), picture_dir)
            }
            else if file_name == ".mp4" || file_name == ".mkv"{
                let video_dir = "Downloaded Videos";
                fs::create_dir_all(video_dir).unwrap();
                std::fs::rename(file_name, format!("{video_dir}/{file_name}")).unwrap();
                println!("Name: {} Moved to {}", file_name.unwrap().path().display(), video_dir)
            }
            else if file_name == ".mp3" || file_name== ".ogg"{
                let music_dir = "Downloaded music";
                fs::create_dir_all(music_dir).unwrap();
                std::fs::rename(file_name, format!("{music_dir}/{file_name}")).unwrap();
                println!("Name: {} Moved to {}", file_name.unwrap().path().display(), music_dir)
            }
        }
    }
}
1 Answers

Use Path::extension to get the file extension. You can use a match block to map the extensions to folders. It's a little awkward since it returns Option<&OsStr> not Option<&str>. We can't write a direct match against string literals but we can get funky with it and use ==.

let entries = fs::read_dir("./").unwrap();
for entry in entries {
    let path = entry.unwrap().path();
    let file_name = match path.file_name() {
        Some(file_name) => file_name,
        None => continue,
    };
    let download_dir = match path.extension() {
        Some(ext) if ext == "jpg" => "Downloaded Pictures",
        Some(ext) if ext == "png" => "Downloaded Pictures",
        Some(ext) if ext == "mp4" => "Downloaded Videos",
        Some(ext) if ext == "mkv" => "Downloaded Videos",
        Some(ext) if ext == "mp3" => "Downloaded music",
        Some(ext) if ext == "ogg" => "Downloaded music",
        _ => continue,
    };
    let download_dir = Path::new(download_dir);
    
    fs::create_dir_all(download_dir).unwrap();
    fs::rename(&path, download_dir.join(file_name)).unwrap();
    println!("Name: {} Moved to {}", path.display(), download_dir.display());
}

Other improvements:

  • Refactored the common code out of the match blocks.
  • Uses Path::join instead of format! to join the download directory and the file name.
Related