You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust如何提取文件扩展名 实现下载目录文件自动分类整理

Rust实现按文件扩展名自动分类移动文件

Rust标准库std::path::Path原生提供了文件扩展名提取能力,不需要手动写字符串切割逻辑,完全可以实现你要的自动分类需求。

你原有代码无法运行的核心问题有3个:

  • 直接拿完整文件路径和.jpg这类后缀字符串做相等判断,永远不可能匹配成功
  • 调用path.display()得到的是用于打印的临时显示结构,不能直接作为路径参数传给文件操作API,会触发类型错误
  • 没有跳过子目录、没有处理无扩展名文件、没有错误兜底,运行时很容易直接panic崩溃

正确提取扩展名的方法

使用Path结构自带的extension()方法即可,该方法返回Option<&OsStr>类型,会自动处理路径分隔符、多段文件名等边界情况,不会出现手动切字符串容易出现的匹配错误。

基础用法示例:

use std::path::Path;

let file_path = Path::new("./travel_photo.jpg");
if let Some(ext) = file_path.extension().and_then(|os_str| os_str.to_str()) {
    // 统一转小写,避免.JPG/.Png这类大写后缀漏匹配
    match ext.to_ascii_lowercase().as_str() {
        "jpg" | "png" | "webp" => println!("图片文件"),
        "mp4" | "mkv" => println!("视频文件"),
        "mp3" | "flac" => println!("音频文件"),
        _ => println!("其他类型文件")
    }
}

注意:extension()返回的扩展名已经去掉了前缀的.,匹配的时候直接写"jpg"即可,不要写成".jpg",否则会匹配失败。

可直接运行的修正版代码

修正版做了以下优化:

  • 自动适配Windows/macOS/Linux的系统下载目录,不需要硬编码路径
  • 遍历目录时自动跳过子目录,仅处理普通文件
  • 扩展名统一转小写匹配,覆盖大写后缀场景
  • 全流程用标准库Path API拼接路径,避免跨平台路径分隔符不兼容问题
  • 增加错误兜底,单个文件操作失败不会导致整个程序崩溃
  • 轮询扫描增加5秒间隔,不会占满CPU资源
use std::fs;
use std::path::PathBuf;

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

// 获取系统默认下载目录,无权限读取时兜底到当前程序运行目录
fn get_download_dir() -> PathBuf {
    if let Some(home) = dirs::home_dir() {
        let download_path = home.join("Downloads");
        if download_path.exists() {
            return download_path;
        }
    }
    PathBuf::from("./")
}

fn main() {
    loop {
        cls();
        let download_dir = get_download_dir();
        println!("正在扫描目录: {}", download_dir.display());

        // 分类规则:(分类目录名, 对应扩展名列表)
        let categories = [
            ("Downloaded Pictures", ["jpg", "jpeg", "png", "gif", "bmp", "webp"]),
            ("Downloaded Videos", ["mp4", "mkv", "mov", "avi", "flv", "webm"]),
            ("Downloaded Music", ["mp3", "ogg", "flac", "wav", "aac"]),
            ("Downloaded Documents", ["pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", "md"]),
            ("Downloaded Archives", ["zip", "rar", "7z", "tar", "gz", "bz2"])
        ];

        let entries = match fs::read_dir(&download_dir) {
            Ok(e) => e,
            Err(err) => {
                println!("读取目录失败: {err}");
                break;
            }
        };

        for entry in entries {
            let entry = match entry {
                Ok(e) => e,
                Err(_) => continue
            };
            let file_path = entry.path();

            // 跳过目录、软链等非普通文件
            if !file_path.is_file() {
                continue;
            }

            // 提取扩展名,无扩展名的文件直接跳过
            let ext = match file_path.extension().and_then(|e| e.to_str()) {
                Some(e) => e.to_ascii_lowercase(),
                None => continue
            };

            // 匹配分类并移动文件
            for (target_dir_name, support_exts) in categories {
                if support_exts.contains(&ext.as_str()) {
                    let target_dir = download_dir.join(target_dir_name);
                    // 分类目录不存在时自动创建
                    if let Err(err) = fs::create_dir_all(&target_dir) {
                        println!("创建目录{}失败: {}", target_dir.display(), err);
                        continue;
                    }

                    let file_name = match file_path.file_name() {
                        Some(n) => n,
                        None => continue
                    };
                    let target_path = target_dir.join(file_name);

                    match fs::rename(&file_path, &target_path) {
                        Ok(_) => println!("已移动: {} -> {}", file_name.to_string_lossy(), target_dir_name),
                        Err(err) => println!("移动文件{}失败: {}", file_name.to_string_lossy(), err)
                    }
                    break;
                }
            }
        }
        // 间隔5秒扫描一次
        std::thread::sleep(std::time::Duration::from_secs(5));
    }
}

使用说明

  • 代码中用dirs库获取系统家目录,需要在Cargo.toml中添加依赖:dirs = "5.0";如果不想引入第三方依赖,直接修改get_download_dir()返回你的下载目录绝对路径即可
  • 可以根据自己的需求修改categories数组里的分类目录和对应扩展名
  • 如果不需要持续监控扫描,把外层loop和最后的sleep逻辑去掉,程序就会执行一次分类后直接退出

内容的提问来源于stack exchange,提问作者user18240098

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 06:03:31