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
相关产品推荐
相关产品推荐

