You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在无竞争条件的情况下修改文件属性?

原子修改Windows文件属性的可行方案

Windows并没有提供你期望的那种ModifyFileAttributes(DWORD addAttributes, DWORD rmAttributes)风格的直接原子API,但可以通过两种可靠方式规避查询-修改的竞争条件:

1. 独占打开文件后操作句柄

通过独占模式打开文件,确保操作期间其他进程无法修改文件属性,以此模拟原子性:

  • 调用CreateFileW时,设置共享模式为0(不允许其他进程读写或修改),同时请求FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES权限。
  • 拿到句柄后,用GetFileInformationByHandle获取当前属性,调整后调用SetFileInformationByHandle更新。
  • 因为文件被独占锁定,这段操作期间其他进程无法干预属性,相当于实现了原子修改逻辑。

示例代码:

HANDLE hFile = CreateFileW(L"C:\\test.txt", 
                           FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
                           0, // 独占访问,无共享权限
                           NULL,
                           OPEN_EXISTING,
                           FILE_ATTRIBUTE_NORMAL,
                           NULL);
if (hFile != INVALID_HANDLE_VALUE) {
    FILE_BASIC_INFO fileInfo;
    if (GetFileInformationByHandle(hFile, &fileInfo)) {
        // 添加只读属性,移除隐藏属性
        fileInfo.FileAttributes |= FILE_ATTRIBUTE_READONLY;
        fileInfo.FileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;
        SetFileInformationByHandle(hFile, FileBasicInfo, &fileInfo, sizeof(fileInfo));
    }
    CloseHandle(hFile);
}

2. 使用NT原生API实现内核级原子更新

通过NtSetInformationFile这个NT内核API,可以直接原子性地写入目标属性值:

  • 该API允许你构造FILE_BASIC_INFORMATION结构,其中的FileAttributes字段会被原子性地写入文件元数据,无需担心中间被其他进程修改。
  • 注意:这是未公开的原生接口,需要链接ntdll.lib,且路径需使用NT格式(如\\?\C:\test.txt)或自行转换。

示例代码:

#include <ntdll.h>

typedef struct _FILE_BASIC_INFORMATION {
    LARGE_INTEGER CreationTime;
    LARGE_INTEGER LastAccessTime;
    LARGE_INTEGER LastWriteTime;
    LARGE_INTEGER ChangeTime;
    ULONG FileAttributes;
} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;

int main() {
    HANDLE hFile = CreateFileW(L"\\\\?\\C:\\test.txt", 
                               FILE_WRITE_ATTRIBUTES,
                               FILE_SHARE_READ | FILE_SHARE_WRITE,
                               NULL,
                               OPEN_EXISTING,
                               FILE_ATTRIBUTE_NORMAL,
                               NULL);
    if (hFile != INVALID_HANDLE_VALUE) {
        FILE_BASIC_INFORMATION fileInfo = {0};
        IO_STATUS_BLOCK ioStatusBlock;
        
        // 可选:先查询当前属性
        NtQueryInformationFile(hFile, &ioStatusBlock, &fileInfo, sizeof(fileInfo), FileBasicInformation);
        
        // 修改属性
        fileInfo.FileAttributes |= FILE_ATTRIBUTE_READONLY;
        fileInfo.FileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;
        
        // 原子写入属性
        NTSTATUS status = NtSetInformationFile(hFile, &ioStatusBlock, &fileInfo, sizeof(fileInfo), FileBasicInformation);
        
        CloseHandle(hFile);
    }
    return 0;
}

关键提示

  • 独占访问方式兼容性更好,适用于绝大多数用户态场景,无需依赖未公开接口。
  • NT API方式是真正的内核级原子操作,但需注意系统版本兼容性,微软不保证该接口长期稳定。
  • 两种方式都需要处理文件打开失败的情况(如文件被其他进程占用)。

内容的提问来源于stack exchange,提问作者lb90

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 22:16:15