关于std::filesystem::file_size()抛出C++异常的疑问与咨询
为什么查询不存在路径会抛出异常?
C++17引入的std::filesystem库设计中,file_size()的默认重载(无error_code参数)会在无法完成核心功能时抛出异常。当目标路径不存在时,函数无法获取文件大小,不符合它“返回已存在文件大小”的语义约定,因此会抛出std::filesystem::filesystem_error异常——这是标准库I/O错误处理模型的一部分,异常用于标识函数无法完成预期任务的场景。
这种情况算不算程序员操作有误?
不一定。如果你的业务逻辑中,文件“可能存在也可能不存在”是正常流程(比如检查用户上传的可选文件),那这属于需要处理的边界场景,而非编程错误。但如果你的逻辑明确假定文件必须存在(比如读取程序依赖的配置文件),此时抛出异常则说明存在操作错误(如路径拼写错误、文件被误删)。
避免异常的可行方法
1. 使用非抛出重载(推荐)
std::filesystem::file_size提供了接受std::error_code&参数的重载,不会抛出异常,而是将错误信息写入该参数。这种方式既避免了异常,还能避免竞态条件(比如先检查文件存在再调用file_size时,文件可能在两次调用之间被删除)。示例代码:
#include <filesystem> #include <system_error> namespace fs = std::filesystem; // 目标路径 fs::path target_path = "example.txt"; std::error_code ec; // 调用非抛出重载 std::uintmax_t file_size = fs::file_size(target_path, ec); if (ec) { // 处理错误 if (ec == std::errc::no_such_file_or_directory) { // 文件不存在的逻辑 } else if (ec == std::errc::permission_denied) { // 权限不足的逻辑 } else { // 其他文件系统错误 } } else { // 成功获取文件大小,执行后续逻辑 }
2. 先检查文件存在(不推荐,存在竞态)
如果一定要先确认文件存在,可调用std::filesystem::exists(),但要注意竞态条件:两次调用之间,文件可能被删除、移动或重命名,导致后续file_size仍可能抛出异常(如果用默认抛出重载)。示例代码:
fs::path target_path = "example.txt"; if (fs::exists(target_path)) { try { auto size = fs::file_size(target_path); // 使用文件大小 } catch (const fs::filesystem_error& e) { // 处理其他异常,比如权限问题 } } else { // 文件不存在的逻辑 }
能否禁用这类“轻微”异常?
不建议通过编译器全局关闭异常检测,这会破坏整个程序的异常处理模型,且无法阻止标准库生成异常的逻辑。标准库已经提供了更合理的解决方案——使用带error_code的非抛出重载,这是专门为需要避免异常的场景设计的官方处理方式。
内容的提问来源于stack exchange,提问作者Robert

