C/C++---_access 和 access 函数 文件/目录状态判断
要理解 _access
和 access
函数,核心是抓住它们的跨平台差异和核心功能(文件/目录状态判断)——两者本质是同一功能在不同系统下的实现,用于检查文件/目录是否存在、或是否具备读写执行权限。
一、核心功能
access
(标准C库)和 _access
(Windows特有扩展)的核心作用是:
判断指定路径的文件/目录是否存在,或是否拥有特定权限(读、写、执行),避免后续操作(如打开、读取、写入文件)因“文件不存在”或“权限不足”报错。
二、跨平台差异:access
vs _access
两者功能完全一致,但存在平台依赖和头文件差异,这是使用时最容易踩坑的点:
特性 | access (POSIX标准,适用于Linux/macOS) | _access (Windows特有,适用于Windows) |
---|---|---|
所属标准 | C标准库(POSIX扩展) | Microsoft C Runtime(MSVC扩展) |
头文件 | <unistd.h> | <io.h> |
函数名前缀 | 无(标准名) | 有下划线(_ ,Windows扩展) |
路径分隔符 | 支持 / (如 /home/user/bg.png ) | 支持 \ (如 C:\data\bg.png ,需转义为 C:\\data\\bg.png ) |
本质区别 | 无功能差异,仅平台适配不同 |
三、函数原型与参数
1. 通用原型(简化版)
// Linux/macOS: access
int access(const char* pathname, int mode);// Windows: _access
int _access(const char* pathname, int mode);
2. 参数说明
参数 | 含义 |
---|---|
pathname | 字符串,指向要检查的文件/目录路径(绝对路径或相对路径) |
mode | 整数,指定检查的“模式”(核心参数,常用值如下) |
3. 关键:mode
模式取值(常用)
mode
决定了函数要检查的具体内容,最常用的是 判断文件是否存在,其次是权限检查:
mode值 | 含义(跨平台通用) | 适用场景 |
---|---|---|
0 | 检查文件/目录是否存在 | 最常用 |
4 | 检查是否拥有读权限 | 读取文件前确认权限(如加载图片前) |
2 | 检查是否拥有写权限 | 写入文件前确认权限(如保存背景图前) |
1 | 检查是否拥有执行权限 | 运行可执行文件前确认(如 .exe 或 ./a.out ) |
6 | 检查是否拥有读+写权限 | 等价于 4 + 2 (需同时满足读写) |
四、返回值说明
函数返回值是判断结果的核心,只有两种可能:
- 返回
0
:成功!表示满足mode
对应的条件(如mode=0
时,文件存在)。 - 返回
-1
:失败!表示不满足条件(如文件不存在、权限不足),或路径无效。
失败原因排查(常用)
返回 -1
时,可通过 errno
(需包含 <errno.h>
)查看具体原因:
#include <errno.h> // 需包含此头文件if (_access("depth_background.png", 0) == -1)
{switch(errno){case ENOENT: // 错误码:文件/目录不存在cout << "错误:背景图不存在" << endl;break;case EACCES: // 错误码:权限不足(如只读文件要写)cout << "错误:没有访问权限" << endl;break;case ENOTDIR: // 错误码:路径中的目录不存在(如 "a/b/c.png" 中 b 不存在)cout << "错误:路径中的目录不存在" << endl;break;}
}
五、实战示例
场景1:Windows环境判断背景图是否存在
#include <io.h> // Windows _access 头文件
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;int main()
{const string bgPath = "depth_background.png"; // 背景图路径Mat background2;// 1. 用 _access 检查背景图是否存在(mode=0)if (_access(bgPath.c_str(), 0) == 0){// 2. 存在则直接加载background2 = imread(bgPath, IMREAD_ANYDEPTH); // 保留深度图16位格式cout << "成功加载已保存的背景图!" << endl;}else{// 3. 不存在则初始化并保存Mat depthMat = imread("current_depth.png", IMREAD_ANYDEPTH); // 实时深度图depthMat.copyTo(background2);imwrite(bgPath, background2); // 保存背景图cout << "首次初始化背景图,并保存到本地!" << endl;}return 0;
}
场景2:跨平台兼容写法(Windows+Linux通用)
为了让代码在不同系统都能运行,用宏定义区分平台:
#include <opencv2/opencv.hpp>
#include <iostream>
#include <errno.h>// 跨平台宏定义:判断文件是否存在
#ifdef _WIN32 // Windows环境
#include <io.h>
#define FILE_EXISTS(path) (_access((path).c_str(), 0) == 0)
#else // Linux/macOS环境
#include <unistd.h>
#define FILE_EXISTS(path) (access((path).c_str(), 0) == 0)
#endifusing namespace cv;
using namespace std;int main()
{const string bgPath = "depth_background.png";Mat background2;if (FILE_EXISTS(bgPath)){background2 = imread(bgPath, IMREAD_ANYDEPTH);cout << "加载背景图成功!" << endl;}else{cout << "背景图不存在,初始化中..." << endl;// 初始化背景逻辑...}return 0;
}
六、注意事项(避坑指南)
-
路径转义问题(Windows):
Windows路径用\
时,需转义为\\
(如C:\\data\\bg.png
),或直接用/
(Windows也支持,如C:/data/bg.png
),避免字符串解析错误。 -
深度图格式适配:
背景图是深度图(通常CV_16UC1
),判断存在后,加载时必须用IMREAD_ANYDEPTH
标志,否则OpenCV会默认转成8位图,丢失深度数据。 -
符号链接问题(Linux):
Linux下access
会跟随符号链接(如ln -s 真实文件 链接文件
),若需不跟随符号链接,用laccess
函数(特殊场景)。 -
权限的“表面性”:
access
仅检查“当前用户是否拥有权限”,不代表后续操作(如fopen
)一定成功(例如检查后文件被删除、权限被修改),但能大幅减少无效操作。
- 核心用途:优先用于文件存在性检查(
mode=0
),其次是权限验证。 - 跨平台关键:Windows用
_access
+<io.h>
,Linux用access
+<unistd.h>
,建议用宏定义兼容。