windows下可用createfile以generic_read和file_share_read|file_share_write尝试打开文件,若失败且getlasterror()返回error_sharing_violation,则表明文件被独占打开;但该方法仅反映当前能否按指定模式打开,并非绝对判定“正在被读”,且无法检测lockfileex等额外锁。

Windows 下用 CreateFile 检测文件是否被独占打开
Windows 没有直接的 API 告诉你“这个文件正被谁读着”,但可以通过尝试以冲突模式打开来间接判断。核心思路是:如果另一个进程以 FILE_SHARE_READ 以外的方式打开了文件(比如没设共享读,或用了 CREATE_ALWAYS 等排他标志),那么你用 GENERIC_READ + FILE_SHARE_WRITE 去开它,CreateFile 就会失败并返回 INVALID_HANDLE_VALUE,且 GetLastError() 为 ERROR_SHARING_VIOLATION。
注意这不是万能检测——它只反映“此刻能否按你的意图打开”,不等于“一定有人在读”。比如对方只是以写方式独占打开但还没读,你也照样被拒。
- 必须指定
dwShareMode为FILE_SHARE_READ | FILE_SHARE_WRITE(你想兼容别人正在读/写) - 不要用
OPEN_ALWAYS或CREATE_ALWAYS,它们自带隐式独占语义,容易误判 - 打开后立刻
CloseHandle,别真去读写,否则可能干扰原进程 - 某些程序(如 Excel、Word)会对文件加额外锁(例如通过
LockFileEx),这种锁CreateFile检不出,需配合其他手段
Linux/macOS 下靠 open + O_NONBLOCK 和 flock 组合试探
Unix-like 系统没有强制的读锁定机制,文件是否“被读”本身不阻塞其他进程打开。真正会阻塞的是显式加的建议性锁(flock)或强制锁(fcntl)。所以检测重点变成:有没有进程持有该文件的写锁或排他读锁?
常用组合是先 open 文件(只读、非阻塞),再用 flock(fd, LOCK_EX | LOCK_NB) 尝试加个独占锁。如果失败且 errno == EWOULDBLOCK,说明已有进程持有了冲突锁(通常是写锁,或另一个 LOCK_EX)。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
-
open(path, O_RDONLY | O_NONBLOCK)必须带O_NONBLOCK,否则flock可能卡住 -
flock是建议锁,依赖所有参与者自觉遵守;绕过它的程序(如直接write不加锁)无法被检出 - 有些服务(如数据库)用
fcntl(F_SETLK)做区域锁,flock对它无效,得换fcntl再试一次 - 注意文件描述符泄漏:每次
open后记得close,哪怕flock失败了
跨平台不可靠:别信 std::filesystem::exists 或文件大小不变
很多人想用“文件存在但打不开”或“连续两次读 size 相同”来推断被占用,这完全不可靠。
-
std::filesystem::exists只查路径是否存在,和锁毫无关系 - 文件被只读打开时,
open/CreateFile往往仍成功(只要对方开了FILE_SHARE_READ或没加flock) - 文件 size 不变 ≠ 没人在读——流式读取、内存映射、日志轮转都可能导致 size 静止
- 即使检测到锁,也无法知道是哪个进程、什么操作类型(读/写/执行)、是否即将释放
真正稳健的做法:改用进程间通信而非文件锁探测
如果你的场景是“等某个生成器写完再处理”,硬盯文件锁是下策。更可靠的是让生产者主动通知消费者——比如写完后创建一个 .done 标记文件,或通过命名管道、Unix domain socket、或 Windows 的 Event 对象发信号。
文件系统不是 IPC 设施,它的锁机制本就不是为协调多进程访问设计的,而是为防止数据损坏。把“等待就绪”逻辑塞进文件操作里,注定要踩竞态、权限、挂载选项(如 NFS、CIFS)等一堆坑。
尤其当涉及网络文件系统或容器环境时,flock 行为可能被禁用或模拟失效,CreateFile 的共享语义也可能被 SMB 服务器重解释。这时候花半天调检测逻辑,不如花二十分钟加个简单的信号文件。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










