等待文件可写
Wait for a file to be writable
我正在开发一种将数据写入文件的工具。
在某些时候,文件可能 "locked" 并且在其他句柄关闭之前不可写。
我可以在循环中使用 CreateFile
API,直到文件可用于写入访问。
但是在循环中使用 CreateFile
我有两个问题:
- 硬盘驱动器(缓存)总是 运行...?!
- 我需要再次调用
CreateFile
以获得具有不同标志的有效写入句柄...?!
所以我的问题是:
等待文件可写并立即获得有效句柄的最佳解决方案是什么?
是否有任何事件解决方案或任何东西,允许"queue/reserve" for a handle once,这样就没有"uncontrolled" race condition with others?
除了一个繁忙的循环,反复尝试打开具有写权限的文件(这闻起来不对 - 如果文件被卡住的进程锁定并且需要重新启动或手动终止,你'永远无法写入它。
您可以写入临时文件并在之后重命名它(您可以告诉 OS 需要进行文件重命名操作,它将在下次启动时执行)。如果您需要追加而不是写入,那么您将必须编写一个过程来将您的临时文件追加到正确的文件中,可能在启动时(编写将哪个文件追加到您的过程读取的文件的位置的说明) .
如果你需要修改一个锁定的文件,那么你只需要尽快锁定它,如果你没有写入权限就拒绝启动程序 - 警告用户就在开头。
您有可能以更好的方式等待:如果文件被锁定写入,您可以假设有人要写入它,因此使用 FindFirstChangeNotification 接收 FILE_NOTIFY_CHANGE_LAST_WRITE 或 FILE_NOTIFY_CHANGE_ATTRIBUTES 事件。它并不完美,因为有人也可以请求独占阅读权限。
我想您可以尝试获取锁定文件的句柄并等待它,因此当它被释放时,您的 WaitForSingleObject 将 return。但是,很有可能不允许您获得不同进程(由安全子系统)拥有的句柄
一个文件可以是 "locked" 有两个原因:
- 一个实际的文件锁 阻止写入,并可能从 读取文件。
- 在没有共享访问权限的情况下(意外或自愿)打开文件这甚至会阻止您打开句柄。如果您已经看到
CreateFile
失败,那很可能是这种情况,而不是真正的锁。
概念上[1]至少有两种方法可以知道没有其他进程在没有忙等待的情况下锁定文件:
- 通过找出谁持有锁并等待进程或线程退出(或者,通过彻底杀死它们...)
- 通过自己锁定文件
谁持有锁?
找出锁的所有者是相当讨厌的,你可以通过 totally undocumented SystemLocksInformation
class 与未记录的 NtQuerySystemInformation
函数(后者是 "only undocumented",但前者的文档太多,以至于很难找到任何信息)。返回的结构解释为 here,它包含一个拥有的线程 ID。
幸好,拿着锁就等于拿着把手。关闭文件句柄将解锁所有文件范围。这意味着:没有把手就没有锁。
换句话说,问题也可以表示为"who is holding an open handle to the file?"。当然,并非所有拥有文件句柄的进程都会锁定文件,但是没有拥有句柄的进程可以保证没有进程锁定文件。
找出哪些进程打开了文件的代码要容易得多(使用重新启动管理器),readily available 在 Raymond Chen 的网站上。
既然您知道哪些进程和线程持有文件句柄和锁,请列出所有 thread/process 句柄并在进程句柄列表中使用 WaitForMultipleObjects
。当进程退出时,所有句柄都关闭。
这也透明地处理了 "lock" 的可能性,因为进程不共享访问权限。
自己锁定文件
您可以使用异步操作的 LockFileEx
。请注意,LockFileEx
需要一个有效的句柄,该句柄已使用 读取或写入权限 打开(可能无法获得写入权限,但读取几乎总是有效——即使你实际上被独占锁阻止读取,如果没有锁,仍然可以创建一个可以读取的句柄。
然后您可以通过 OVERLAPPED
结构中的事件或完成端口等待异步锁定完成,同时甚至可以做其他有用的事情。锁定文件后,您就知道没有其他人锁定过它。
[1] 措辞 "conceptually" 表明我很确定这两种方法都行得通,但我还没有测试过它们。
我正在开发一种将数据写入文件的工具。
在某些时候,文件可能 "locked" 并且在其他句柄关闭之前不可写。
我可以在循环中使用 CreateFile
API,直到文件可用于写入访问。
但是在循环中使用 CreateFile
我有两个问题:
- 硬盘驱动器(缓存)总是 运行...?!
- 我需要再次调用
CreateFile
以获得具有不同标志的有效写入句柄...?!
所以我的问题是:
等待文件可写并立即获得有效句柄的最佳解决方案是什么?
是否有任何事件解决方案或任何东西,允许"queue/reserve" for a handle once,这样就没有"uncontrolled" race condition with others?
除了一个繁忙的循环,反复尝试打开具有写权限的文件(这闻起来不对 - 如果文件被卡住的进程锁定并且需要重新启动或手动终止,你'永远无法写入它。
您可以写入临时文件并在之后重命名它(您可以告诉 OS 需要进行文件重命名操作,它将在下次启动时执行)。如果您需要追加而不是写入,那么您将必须编写一个过程来将您的临时文件追加到正确的文件中,可能在启动时(编写将哪个文件追加到您的过程读取的文件的位置的说明) .
如果你需要修改一个锁定的文件,那么你只需要尽快锁定它,如果你没有写入权限就拒绝启动程序 - 警告用户就在开头。
您有可能以更好的方式等待:如果文件被锁定写入,您可以假设有人要写入它,因此使用 FindFirstChangeNotification 接收 FILE_NOTIFY_CHANGE_LAST_WRITE 或 FILE_NOTIFY_CHANGE_ATTRIBUTES 事件。它并不完美,因为有人也可以请求独占阅读权限。
我想您可以尝试获取锁定文件的句柄并等待它,因此当它被释放时,您的 WaitForSingleObject 将 return。但是,很有可能不允许您获得不同进程(由安全子系统)拥有的句柄
一个文件可以是 "locked" 有两个原因:
- 一个实际的文件锁 阻止写入,并可能从 读取文件。
- 在没有共享访问权限的情况下(意外或自愿)打开文件这甚至会阻止您打开句柄。如果您已经看到
CreateFile
失败,那很可能是这种情况,而不是真正的锁。
概念上[1]至少有两种方法可以知道没有其他进程在没有忙等待的情况下锁定文件:
- 通过找出谁持有锁并等待进程或线程退出(或者,通过彻底杀死它们...)
- 通过自己锁定文件
谁持有锁?
找出锁的所有者是相当讨厌的,你可以通过 totally undocumented SystemLocksInformation
class 与未记录的 NtQuerySystemInformation
函数(后者是 "only undocumented",但前者的文档太多,以至于很难找到任何信息)。返回的结构解释为 here,它包含一个拥有的线程 ID。
幸好,拿着锁就等于拿着把手。关闭文件句柄将解锁所有文件范围。这意味着:没有把手就没有锁。
换句话说,问题也可以表示为"who is holding an open handle to the file?"。当然,并非所有拥有文件句柄的进程都会锁定文件,但是没有拥有句柄的进程可以保证没有进程锁定文件。
找出哪些进程打开了文件的代码要容易得多(使用重新启动管理器),readily available 在 Raymond Chen 的网站上。
既然您知道哪些进程和线程持有文件句柄和锁,请列出所有 thread/process 句柄并在进程句柄列表中使用 WaitForMultipleObjects
。当进程退出时,所有句柄都关闭。
这也透明地处理了 "lock" 的可能性,因为进程不共享访问权限。
自己锁定文件
您可以使用异步操作的 LockFileEx
。请注意,LockFileEx
需要一个有效的句柄,该句柄已使用 读取或写入权限 打开(可能无法获得写入权限,但读取几乎总是有效——即使你实际上被独占锁阻止读取,如果没有锁,仍然可以创建一个可以读取的句柄。
然后您可以通过 OVERLAPPED
结构中的事件或完成端口等待异步锁定完成,同时甚至可以做其他有用的事情。锁定文件后,您就知道没有其他人锁定过它。
[1] 措辞 "conceptually" 表明我很确定这两种方法都行得通,但我还没有测试过它们。