如何向C运行时open()传递FILE_ATTRIBUTE常量或实现Win32包装器?
解决方案
针对你的需求,有两种可靠的实现方式,适配使用标准CRT函数的遗留Windows C应用:
1. 直接通过MSVC CRT的_open()传递Win32文件属性
MSVC的C运行时(CRT)对_open()(下划线开头的CRT专属函数,非POSIX标准open)做了扩展:当你指定_O_CREAT标志创建文件时,mode参数的高16位可以直接传递Win32的FILE_ATTRIBUTE_*常量,低16位保留为POSIX风格的文件权限(如_S_IWRITE)。
示例代码:
#include <fcntl.h> #include <sys/stat.h> #include <windows.h> // 创建一个隐藏文件 int fd = _open("hidden.txt", _O_WRONLY | _O_CREAT | _O_TRUNC, _S_IWRITE | (FILE_ATTRIBUTE_HIDDEN << 16));
注意事项:
- 仅适用于创建新文件的场景(必须带
_O_CREAT),打开已有文件时该方式无法修改属性 - 此行为是MSVC CRT的专属扩展,其他Windows编译器(如MinGW)可能不支持
2. 封装Win32 API实现自定义文件打开逻辑
如果需要更灵活的控制(比如打开已有文件时指定属性、处理Unicode路径等),可以直接调用Win32的CreateFile API,再通过CRT的_open_osfhandle()函数将Win32句柄转换为标准CRT文件描述符。
封装函数示例
#include <windows.h> #include <fcntl.h> #include <io.h> #include <errno.h> int win32_open(const char* path, int crt_flags, DWORD win32_attrs) { // 将CRT标志映射为Win32参数 DWORD desired_access = 0; DWORD creation_disposition = 0; // 处理访问权限 if (crt_flags & _O_RDONLY) { desired_access = GENERIC_READ; } else if (crt_flags & _O_WRONLY) { desired_access = GENERIC_WRITE; } else if (crt_flags & _O_RDWR) { desired_access = GENERIC_READ | GENERIC_WRITE; } // 处理创建/打开模式 if (crt_flags & _O_CREAT) { if (crt_flags & _O_TRUNC) { creation_disposition = CREATE_ALWAYS; } else { creation_disposition = CREATE_NEW; } } else if (crt_flags & _O_TRUNC) { creation_disposition = TRUNCATE_EXISTING; } else { creation_disposition = OPEN_EXISTING; } // 调用Win32 CreateFile HANDLE hFile = CreateFileA( path, desired_access, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, creation_disposition, FILE_ATTRIBUTE_NORMAL | win32_attrs, NULL ); if (hFile == INVALID_HANDLE_VALUE) { _set_errno(GetLastError()); // 同步Win32错误码到CRT的errno return -1; } // 将Win32句柄转换为CRT文件描述符 int fd = _open_osfhandle((intptr_t)hFile, crt_flags); if (fd == -1) { CloseHandle(hFile); // 转换失败时手动关闭句柄 return -1; } return fd; }
使用示例
// 打开或创建一个加密的可读可写文件 int fd = win32_open("encrypted.txt", _O_RDWR | _O_CREAT, FILE_ATTRIBUTE_ENCRYPTED); if (fd != -1) { // 用标准CRT函数操作:write/read/close等 write(fd, "test data", 9); _close(fd); // 关闭描述符时会自动关闭对应的Win32句柄 }
注意事项:
_open_osfhandle需要包含<io.h>头文件- 转换后的文件描述符完全兼容标准CRT的
read/write/close等函数 - 如果需要处理Unicode路径,替换为
CreateFileW并传入宽字符路径即可
内容的提问来源于stack exchange,提问作者PasterOfMuppets
相关产品推荐
相关产品推荐

