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

Rust中FileMetaData处理非HEIC文件:替换panic!实现错误抛出或跳过

解决Rust中文件格式校验的错误处理问题

1. 定义自定义错误类型

先创建自定义错误枚举,覆盖所有可能的错误场景,同时实现Display和Error trait,方便错误信息打印与传播:

use std::fmt;
use std::error::Error;
use std::fs;
use std::path::Path;

#[derive(Debug)]
enum CustomError {
    UnsupportedFileFormat,
    InvalidPath,
    IoError(std::io::Error),
}

impl fmt::Display for CustomError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            CustomError::UnsupportedFileFormat => write!(f, "仅支持HEIC格式文件"),
            CustomError::InvalidPath => write!(f, "无效的文件路径"),
            CustomError::IoError(e) => write!(f, "IO错误: {}", e),
        }
    }
}

impl Error for CustomError {}

// 实现从IO错误到自定义错误的自动转换
impl From<std::io::Error> for CustomError {
    fn from(e: std::io::Error) -> Self {
        CustomError::IoError(e)
    }
}

2. 修改FileMetaData的方法返回Result

将new和get_file_name的返回值改为Result类型,替换所有unwrap为错误处理逻辑,彻底移除panic!:

struct FileMetaData {
    name: String,
    directory: bool,
    path: String,
}

impl FileMetaData {
    // 现在返回Result,出错时返回错误信息而非直接崩溃
    fn new(path: &str) -> Result<Self, CustomError> {
        let is_dir = Self::is_directory(path)?;
        Ok(Self {
            name: Self::get_file_name(path)?.to_string(),
            directory: is_dir,
            path: path.to_string(),
        })
    }

    fn get_file_name(path: &str) -> Result<&str, CustomError> {
        let file_path = Path::new(path);
        // 处理文件名为空的情况
        let file_name_os_str = file_path.file_stem().ok_or(CustomError::InvalidPath)?;
        // 处理无法转换为UTF-8的文件名
        let file_name = file_name_os_str.to_str().ok_or(CustomError::InvalidPath)?;

        if !Self::is_directory(path)? {
            // 处理无扩展名的文件
            let extension = file_path.extension()
                .ok_or(CustomError::UnsupportedFileFormat)?
                .to_str()
                .ok_or(CustomError::InvalidPath)?;
            if extension != "heic" {
                return Err(CustomError::UnsupportedFileFormat);
            }
        }

        Ok(file_name)
    }

    // 修改为返回Result,捕获权限不足等IO错误
    fn is_directory(path: &str) -> Result<bool, CustomError> {
        let metadata = fs::metadata(path)?;
        Ok(metadata.is_dir())
    }
}

3. 针对两种场景分别处理错误

处理单个文件

单个文件场景下,若校验失败直接打印错误并退出程序:

fn process_single_file(file_path: &str) {
    let file_metadata = FileMetaData::new(file_path).unwrap_or_else(|e| {
        eprintln!("处理单个文件失败: {}", e);
        std::process::exit(1);
    });
    // 后续处理逻辑
    println!("处理单个文件: {}", file_metadata.name);
}

处理目录

目录场景下,遇到不支持的文件仅打印错误,继续处理其他文件:

fn process_directory(path: &str) -> Result<(), CustomError> {
    let entries = fs::read_dir(path)?
        .map(|res| res.map(|e| e.path()))
        .collect::<Result<Vec<_>, std::io::Error>>()?;

    for entry in entries {
        // 处理无法转换为UTF-8的路径
        let Some(file_path) = entry.to_str() else {
            eprintln!("跳过无效路径: {:?}", entry);
            continue;
        };

        match FileMetaData::new(file_path) {
            Ok(file_metadata) => {
                // 处理有效的文件/目录
                if file_metadata.directory {
                    println!("发现目录: {}", file_metadata.name);
                } else {
                    println!("处理文件: {}", file_metadata.name);
                }
            },
            Err(e) => {
                // 仅打印错误,继续处理下一个文件
                eprintln!("跳过文件 {}: {}", file_path, e);
            }
        }
    }
    Ok(())
}

核心修改点总结

  • 用Result替代panic!,让错误显式传播而非直接崩溃程序
  • 自定义错误类型覆盖所有可能的错误场景,提供清晰的错误提示
  • 单个文件场景用unwrap_or_else处理错误并退出,目录场景用match捕获错误并跳过当前文件
  • 替换所有unwrap为ok_or或?,消除潜在的崩溃风险

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 22:55:16