c++如何处理读取文件过程中的权限拒绝异常_std::error_code捕获【详解】

梦枫大大_9349

梦枫大大_9349

2026-03-24

283人浏览

原创

c++中无法通过std::ifstream获取系统级错误码,必须使用std::filesystem函数带std::error_code&参数的重载版本(如status(path, ec))或直接调用系统api(open/createfilew)才能捕获eacces等真实错误。

c++如何处理读取文件过程中的权限拒绝异常_std::error_code捕获【详解】

std::filesystem::open_file 失败时拿不到 std::error_code?

不是 std::filesystem::open_file —— C++ 标准库压根没有这个函数。你真正调用的,大概率是 std::ifstream 构造或 open(),它底层失败时不会抛出带 std::error_code 的异常,而是设 failbit 或直接抛 std::ios_base::failure(需提前开启异常掩码)。

想拿到系统级错误码(比如 EACCES),必须绕过流封装,用 std::filesystem::status() 或直接调 open()(POSIX)/ CreateFileW(Windows)。

  • 用 std::ifstream 时,is_open() 返回 false 或 !ifs 为真,但无法区分“文件不存在”和“权限拒绝”
  • 开启异常:在构造后立刻调 ifs.exceptions(std::ios_base::failbit | std::ios_base::badbit),但抛出的是 std::ios_base::failure,其 .code() 默认是 std::errc::success,不反映真实 errno
  • 真正能拿到 std::error_code 的路径:先用 std::filesystem::status(path, ec) 检查权限,或用 std::filesystem::can_write(path)、std::filesystem::exists(path) 辅助判断

捕获 EACCES 必须用 std::error_code 参数重载

std::filesystem 的多数函数都提供两套接口:抛异常版(无 ec 参数)和填错码版(带 std::error_code& ec)。只有后者才能拿到原始系统错误,比如 EACCES。

例如读取前验证可访问性:

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载
std::error_code ec;
auto s = std::filesystem::status("/etc/shadow", ec);
if (ec) {
    if (ec.value() == static_cast<int>(std::errc::permission_denied)) {
        // 真实权限拒绝
    }
}</int>
  • 别写 if (ec) 就完事 —— ec 非空只代表出错,具体值要查 ec.value() 并映射到 std::errc
  • Windows 下 std::errc::permission_denied 对应 ERROR_ACCESS_DENIED,但 std::filesystem::status() 在多数实现中会做合理转换
  • 注意:std::filesystem::status() 本身也可能因权限问题失败(比如目录不可执行),此时 ec 是 std::errc::permission_denied,但不代表目标文件一定不可读 —— 它只是无法获取元信息

std::ifstream + errno 是最直接的 fallback 方案

当 std::filesystem 不可用(比如旧编译器)或你需要精确控制 open 行为时,直接调系统 API 最可靠。C++17 起可安全依赖 errno 值(线程局部),只要你在系统调用后立刻检查。

POSIX 示例:

#include <fcntl.h>
#include <cerrno>
int fd = open("/root/file.txt", O_RDONLY);
if (fd == -1) {
    if (errno == EACCES) {
        // 权限拒绝
    }
}</cerrno></fcntl.h>
  • 不要在中间插入任何可能改写 errno 的调用(如 printf、std::cout)
  • std::ifstream 构造失败后,errno 不保证有效 —— 流内部可能已覆盖它,所以不能依赖 errno 解释流错误
  • Windows 下用 CreateFileW,失败时调 GetLastError(),对应 ERROR_ACCESS_DENIED;别用 _doserrno,它不可靠

std::error_code 和 std::errc::xxx 的类型匹配陷阱

std::error_code 的 value() 是 int,但 std::errc 枚举值不是裸 int —— 直接比较 ec.value() == std::errc::permission_denied 可能失败(隐式转换问题)。

  • 正确写法:ec == std::errc::permission_denied(std::error_code 重载了 ==)
  • 错误写法:ec.value() == static_cast<int>(std::errc::permission_denied)</int> —— 在某些标准库实现中,std::errc 值可能被包装成其他域(domain),导致数值不等
  • 更安全的判断:ec.category() == std::system_category() && ec.value() == EACCES(POSIX)或 ec.value() == ERROR_ACCESS_DENIED(Windows),但失去跨平台性

权限异常不是“有没有错”的问题,而是“错得够不够细”的问题。漏掉 ec 参数、混淆 value() 和枚举比较、在流操作后查 errno —— 这三处一踩,就只能打印“打开失败”,再没法告诉用户到底是路径错了,还是 sudo 忘了。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

c++速学教程(入门到精通)
c++速学教程(入门到精通)

c++怎么学习?c++怎么入门?c++在哪学?c++怎么学才快?不用担心,这里为大家提供了c++速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
printf用法大全
printf用法大全

php中文网为大家提供printf用法大全,以及其他printf函数的相关文章、相关下载资源以及各种相关课程,供大家免费下载体验。

2023.06.20

808

5

fprintf和printf的区别
fprintf和printf的区别

fprintf和printf的区别在于输出的目标不同,printf输出到标准输出流,而fprintf输出到指定的文件流。根据需要选择合适的函数来进行输出操作。更多关于fprintf和printf的相关文章详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.28

1029

10

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.02

6579

3

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.08.29

3185

6

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

2025.08.29

4108

10

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

2025.08.29

2825

10

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

2023.10.19

3168

3

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

2025.10.17

5009

12

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2025.12.29

3789

9

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习